source: mainline/uspace/lib/c/generic/loc.c@ 7d7f5e3

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7d7f5e3 was 7d7f5e3, checked in by Jiri Svoboda <jiri@…>, 22 months ago

loc_server_register() should be callable more than once (implementation)

We create a new session for each loc_server_register() / loc_srv_t
object. Alternatively we could multiplex all to a single connection
and then demultiplex them in the server, but this seemed simpler
at the moment.

We add a test case to libc test suite.

  • Property mode set to 100644
File size: 19.0 KB
RevLine 
[15f3c3f]1/*
[4c6fd56]2 * Copyright (c) 2023 Jiri Svoboda
[15f3c3f]3 * Copyright (c) 2007 Josef Cejka
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <str.h>
31#include <ipc/services.h>
32#include <ns.h>
33#include <ipc/loc.h>
34#include <loc.h>
35#include <fibril_synch.h>
36#include <async.h>
37#include <errno.h>
[38d150e]38#include <stdlib.h>
[3e6a98c5]39#include <stdbool.h>
[15f3c3f]40
41static FIBRIL_MUTEX_INITIALIZE(loc_cons_block_mutex);
42static FIBRIL_MUTEX_INITIALIZE(loc_consumer_mutex);
43
[12f9f0d0]44static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex);
45static bool loc_callback_created = false;
[a6240a31]46static loc_cat_change_cb_t cat_change_cb = NULL;
[e89a06a]47static void *cat_change_arg = NULL;
[12f9f0d0]48
[15f3c3f]49static async_sess_t *loc_cons_block_sess = NULL;
50static async_sess_t *loc_consumer_sess = NULL;
51
[984a9ba]52static void loc_cb_conn(ipc_call_t *icall, void *arg)
[12f9f0d0]53{
54 while (true) {
55 ipc_call_t call;
[984a9ba]56 async_get_call(&call);
[a35b458]57
[fafb8e5]58 if (!ipc_get_imethod(&call)) {
[889cdb1]59 async_answer_0(&call, EOK);
[12f9f0d0]60 return;
61 }
[a35b458]62
[fafb8e5]63 switch (ipc_get_imethod(&call)) {
[12f9f0d0]64 case LOC_EVENT_CAT_CHANGE:
65 fibril_mutex_lock(&loc_callback_mutex);
[a6240a31]66 loc_cat_change_cb_t cb_fun = cat_change_cb;
[e89a06a]67 void *cb_arg = cat_change_arg;
[12f9f0d0]68 fibril_mutex_unlock(&loc_callback_mutex);
[a35b458]69
[984a9ba]70 async_answer_0(&call, EOK);
[a35b458]71
[a6240a31]72 if (cb_fun != NULL)
[e89a06a]73 (*cb_fun)(cb_arg);
[a35b458]74
[12f9f0d0]75 break;
76 default:
[984a9ba]77 async_answer_0(&call, ENOTSUP);
[12f9f0d0]78 }
79 }
80}
81
[15f3c3f]82static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
83 async_sess_t **dst)
84{
85 fibril_mutex_lock(mtx);
[a35b458]86
[15f3c3f]87 if ((*dst == NULL) && (src != NULL))
88 *dst = src;
[a35b458]89
[15f3c3f]90 fibril_mutex_unlock(mtx);
91}
92
[a6240a31]93/** Create callback
94 *
95 * Must be called with loc_callback_mutex locked.
96 *
97 * @return EOK on success.
98 *
99 */
[b7fd2a0]100static errno_t loc_callback_create(void)
[12f9f0d0]101{
102 if (!loc_callback_created) {
[a6240a31]103 async_exch_t *exch =
[7d7f5e3]104 loc_exchange_begin_blocking();
[a35b458]105
[12f9f0d0]106 ipc_call_t answer;
107 aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
[a35b458]108
[f9b2cb4c]109 port_id_t port;
[b7fd2a0]110 errno_t rc = async_create_callback_port(exch, INTERFACE_LOC_CB, 0, 0,
[f9b2cb4c]111 loc_cb_conn, NULL, &port);
[a35b458]112
[12f9f0d0]113 loc_exchange_end(exch);
[a35b458]114
[12f9f0d0]115 if (rc != EOK)
[a6240a31]116 return rc;
[a35b458]117
[b7fd2a0]118 errno_t retval;
[cd66f3c]119 async_wait_for(req, &retval);
120 if (retval != EOK)
121 return retval;
[a35b458]122
[12f9f0d0]123 loc_callback_created = true;
124 }
[a35b458]125
[a6240a31]126 return EOK;
[12f9f0d0]127}
128
[15f3c3f]129/** Start an async exchange on the loc session (blocking).
130 *
131 * @return New exchange.
132 *
133 */
[7d7f5e3]134async_exch_t *loc_exchange_begin_blocking(void)
[15f3c3f]135{
[7d7f5e3]136 fibril_mutex_lock(&loc_cons_block_mutex);
[a35b458]137
[7d7f5e3]138 while (loc_cons_block_sess == NULL) {
139 clone_session(&loc_consumer_mutex, loc_consumer_sess,
140 &loc_cons_block_sess);
[a35b458]141
[7d7f5e3]142 if (loc_cons_block_sess == NULL)
143 loc_cons_block_sess =
144 service_connect_blocking(SERVICE_LOC,
145 INTERFACE_LOC_CONSUMER, 0, NULL);
146 }
[a35b458]147
[7d7f5e3]148 fibril_mutex_unlock(&loc_cons_block_mutex);
[a35b458]149
[7d7f5e3]150 clone_session(&loc_consumer_mutex, loc_cons_block_sess,
151 &loc_consumer_sess);
[a35b458]152
[7d7f5e3]153 return async_exchange_begin(loc_cons_block_sess);
[15f3c3f]154}
155
156/** Start an async exchange on the loc session.
157 *
158 * @return New exchange.
159 *
160 */
[7d7f5e3]161async_exch_t *loc_exchange_begin(void)
[15f3c3f]162{
[7d7f5e3]163 fibril_mutex_lock(&loc_consumer_mutex);
[a35b458]164
[7d7f5e3]165 if (loc_consumer_sess == NULL)
166 loc_consumer_sess =
167 service_connect(SERVICE_LOC,
168 INTERFACE_LOC_CONSUMER, 0, NULL);
[a35b458]169
[7d7f5e3]170 fibril_mutex_unlock(&loc_consumer_mutex);
[a35b458]171
[7d7f5e3]172 if (loc_consumer_sess == NULL)
[15f3c3f]173 return NULL;
[7d7f5e3]174
175 return async_exchange_begin(loc_consumer_sess);
[15f3c3f]176}
177
178/** Finish an async exchange on the loc session.
179 *
180 * @param exch Exchange to be finished.
181 *
182 */
183void loc_exchange_end(async_exch_t *exch)
184{
185 async_exchange_end(exch);
186}
187
[4c6fd56]188/** Register new server with loc.
189 *
190 * @param name Server name
191 * @param rsrv Place to store new server object on success
192 * @return EOK on succes or an error code
193 */
194errno_t loc_server_register(const char *name, loc_srv_t **rsrv)
[15f3c3f]195{
[4c6fd56]196 async_exch_t *exch;
197 loc_srv_t *srv;
198
199 srv = calloc(1, sizeof(loc_srv_t));
200 if (srv == NULL)
201 return ENOMEM;
202
[7d7f5e3]203 srv->sess = service_connect_blocking(SERVICE_LOC,
204 INTERFACE_LOC_SUPPLIER, 0, NULL);
205 if (srv->sess == NULL) {
206 free(srv);
207 return ENOMEM;
208 }
209
210 exch = async_exchange_begin(srv->sess);
[a35b458]211
[15f3c3f]212 ipc_call_t answer;
213 aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
[b7fd2a0]214 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]215
[15f3c3f]216 if (retval != EOK) {
[50b581d]217 async_forget(req);
[7d7f5e3]218 async_exchange_end(exch);
219 async_hangup(srv->sess);
[4c6fd56]220 free(srv);
[15f3c3f]221 return retval;
222 }
[a35b458]223
[9b1baac]224 async_connect_to_me(exch, INTERFACE_ANY, 0, 0);
[0239846]225
226 /*
227 * First wait for the answer and then end the exchange. The opposite
228 * order is generally wrong because it may lead to a deadlock under
229 * certain circumstances.
230 */
231 async_wait_for(req, &retval);
[7d7f5e3]232 async_exchange_end(exch);
[a35b458]233
[4c6fd56]234 if (retval != EOK) {
[7d7f5e3]235 async_hangup(srv->sess);
[4c6fd56]236 free(srv);
237 return retval;
238 }
239
240 *rsrv = srv;
[15f3c3f]241 return retval;
242}
243
[4c6fd56]244/** Unregister server from loc.
245 *
246 * Unregister server and free server object.
247 *
248 * @param srv Server object
249 */
250void loc_server_unregister(loc_srv_t *srv)
251{
[7d7f5e3]252 async_hangup(srv->sess);
[4c6fd56]253 free(srv);
254}
255
[d0dd7b5]256/** Register new service.
[15f3c3f]257 *
[4c6fd56]258 * @param srv Server object
259 * @param fqsn Fully qualified service name
260 * @param sid Service ID of new service
[15f3c3f]261 *
262 */
[4c6fd56]263errno_t loc_service_register(loc_srv_t *srv, const char *fqsn,
264 service_id_t *sid)
[15f3c3f]265{
[7d7f5e3]266 async_exch_t *exch = async_exchange_begin(srv->sess);
[15f3c3f]267 ipc_call_t answer;
[f9b2cb4c]268 aid_t req = async_send_0(exch, LOC_SERVICE_REGISTER, &answer);
[b7fd2a0]269 errno_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
[a35b458]270
[15f3c3f]271 if (retval != EOK) {
[50b581d]272 async_forget(req);
[7d7f5e3]273 async_exchange_end(exch);
[15f3c3f]274 return retval;
275 }
[a35b458]276
[0239846]277 /*
278 * First wait for the answer and then end the exchange. The opposite
279 * order is generally wrong because it may lead to a deadlock under
280 * certain circumstances.
281 */
[15f3c3f]282 async_wait_for(req, &retval);
[7d7f5e3]283 async_exchange_end(exch);
[a35b458]284
[15f3c3f]285 if (retval != EOK) {
[d0dd7b5]286 if (sid != NULL)
287 *sid = -1;
[a35b458]288
[15f3c3f]289 return retval;
290 }
[a35b458]291
[d0dd7b5]292 if (sid != NULL)
[fafb8e5]293 *sid = (service_id_t) ipc_get_arg1(&answer);
[a35b458]294
[15f3c3f]295 return retval;
296}
297
[d0dd7b5]298/** Unregister service.
299 *
[4c6fd56]300 * @param srv Server object
301 * @param sid Service ID
[d0dd7b5]302 */
[4c6fd56]303errno_t loc_service_unregister(loc_srv_t *srv, service_id_t sid)
[d0dd7b5]304{
305 async_exch_t *exch;
[b7fd2a0]306 errno_t retval;
[a35b458]307
[7d7f5e3]308 exch = async_exchange_begin(srv->sess);
[d0dd7b5]309 retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
[7d7f5e3]310 async_exchange_end(exch);
[a35b458]311
[b7fd2a0]312 return (errno_t)retval;
[15f3c3f]313}
314
[b7fd2a0]315errno_t loc_service_get_id(const char *fqdn, service_id_t *handle,
[15f3c3f]316 unsigned int flags)
317{
318 async_exch_t *exch;
[a35b458]319
[15f3c3f]320 if (flags & IPC_FLAG_BLOCKING)
[7d7f5e3]321 exch = loc_exchange_begin_blocking();
[15f3c3f]322 else {
[7d7f5e3]323 exch = loc_exchange_begin();
[15f3c3f]324 if (exch == NULL)
325 return errno;
326 }
[a35b458]327
[15f3c3f]328 ipc_call_t answer;
329 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
330 &answer);
[b7fd2a0]331 errno_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
[a35b458]332
[15f3c3f]333 loc_exchange_end(exch);
[a35b458]334
[15f3c3f]335 if (retval != EOK) {
[50b581d]336 async_forget(req);
[15f3c3f]337 return retval;
338 }
[a35b458]339
[15f3c3f]340 async_wait_for(req, &retval);
[a35b458]341
[15f3c3f]342 if (retval != EOK) {
343 if (handle != NULL)
344 *handle = (service_id_t) -1;
[a35b458]345
[15f3c3f]346 return retval;
347 }
[a35b458]348
[15f3c3f]349 if (handle != NULL)
[fafb8e5]350 *handle = (service_id_t) ipc_get_arg1(&answer);
[a35b458]351
[15f3c3f]352 return retval;
353}
354
[763e0cd]355/** Get object name.
[cce8a83]356 *
[763e0cd]357 * Provided ID of an object, return its name.
[cce8a83]358 *
[763e0cd]359 * @param method IPC method
360 * @param id Object ID
[cce8a83]361 * @param name Place to store pointer to new string. Caller should
362 * free it using free().
[cde999a]363 * @return EOK on success or an error code
[cce8a83]364 */
[b7fd2a0]365static errno_t loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
[cce8a83]366{
367 async_exch_t *exch;
368 char name_buf[LOC_NAME_MAXLEN + 1];
[45058baa]369 ipc_call_t dreply;
370 size_t act_size;
[b7fd2a0]371 errno_t dretval;
[a35b458]372
[cce8a83]373 *name = NULL;
[7d7f5e3]374 exch = loc_exchange_begin_blocking();
[a35b458]375
[cce8a83]376 ipc_call_t answer;
[763e0cd]377 aid_t req = async_send_1(exch, method, id, &answer);
[45058baa]378 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
379 &dreply);
380 async_wait_for(dreq, &dretval);
[a35b458]381
[cce8a83]382 loc_exchange_end(exch);
[a35b458]383
[45058baa]384 if (dretval != EOK) {
[50b581d]385 async_forget(req);
[45058baa]386 return dretval;
[cce8a83]387 }
[a35b458]388
[b7fd2a0]389 errno_t retval;
[cce8a83]390 async_wait_for(req, &retval);
[a35b458]391
[cce8a83]392 if (retval != EOK)
393 return retval;
[a35b458]394
[fafb8e5]395 act_size = ipc_get_arg2(&dreply);
[45058baa]396 assert(act_size <= LOC_NAME_MAXLEN);
397 name_buf[act_size] = '\0';
398
[cce8a83]399 *name = str_dup(name_buf);
400 if (*name == NULL)
401 return ENOMEM;
[a35b458]402
[cce8a83]403 return EOK;
404}
405
[763e0cd]406/** Get category name.
407 *
408 * Provided ID of a service, return its name.
409 *
410 * @param cat_id Category ID
411 * @param name Place to store pointer to new string. Caller should
412 * free it using free().
[cde999a]413 * @return EOK on success or an error code
[763e0cd]414 */
[b7fd2a0]415errno_t loc_category_get_name(category_id_t cat_id, char **name)
[763e0cd]416{
417 return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
418}
419
420/** Get service name.
421 *
422 * Provided ID of a service, return its name.
423 *
424 * @param svc_id Service ID
425 * @param name Place to store pointer to new string. Caller should
426 * free it using free().
[cde999a]427 * @return EOK on success or an error code
[763e0cd]428 */
[b7fd2a0]429errno_t loc_service_get_name(service_id_t svc_id, char **name)
[763e0cd]430{
431 return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
432}
[cce8a83]433
[a3fcfba]434/** Get service server name.
435 *
436 * Provided ID of a service, return the name of its server.
437 *
438 * @param svc_id Service ID
439 * @param name Place to store pointer to new string. Caller should
440 * free it using free().
[cde999a]441 * @return EOK on success or an error code
[a3fcfba]442 */
[b7fd2a0]443errno_t loc_service_get_server_name(service_id_t svc_id, char **name)
[a3fcfba]444{
445 return loc_get_name_internal(LOC_SERVICE_GET_SERVER_NAME, svc_id, name);
446}
447
[b7fd2a0]448errno_t loc_namespace_get_id(const char *name, service_id_t *handle,
[15f3c3f]449 unsigned int flags)
450{
451 async_exch_t *exch;
[a35b458]452
[15f3c3f]453 if (flags & IPC_FLAG_BLOCKING)
[7d7f5e3]454 exch = loc_exchange_begin_blocking();
[15f3c3f]455 else {
[7d7f5e3]456 exch = loc_exchange_begin();
[15f3c3f]457 if (exch == NULL)
458 return errno;
459 }
[a35b458]460
[15f3c3f]461 ipc_call_t answer;
462 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
463 &answer);
[b7fd2a0]464 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]465
[15f3c3f]466 loc_exchange_end(exch);
[a35b458]467
[15f3c3f]468 if (retval != EOK) {
[50b581d]469 async_forget(req);
[15f3c3f]470 return retval;
471 }
[a35b458]472
[15f3c3f]473 async_wait_for(req, &retval);
[a35b458]474
[15f3c3f]475 if (retval != EOK) {
476 if (handle != NULL)
477 *handle = (service_id_t) -1;
[a35b458]478
[15f3c3f]479 return retval;
480 }
[a35b458]481
[15f3c3f]482 if (handle != NULL)
[fafb8e5]483 *handle = (service_id_t) ipc_get_arg1(&answer);
[a35b458]484
[15f3c3f]485 return retval;
486}
487
[cc574511]488/** Get category ID.
489 *
490 * Provided name of a category, return its ID.
491 *
492 * @param name Category name
493 * @param cat_id Place to store ID
494 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
[cde999a]495 * @return EOK on success or an error code
[cc574511]496 */
[b7fd2a0]497errno_t loc_category_get_id(const char *name, category_id_t *cat_id,
[cc574511]498 unsigned int flags)
499{
500 async_exch_t *exch;
[a35b458]501
[cc574511]502 if (flags & IPC_FLAG_BLOCKING)
[7d7f5e3]503 exch = loc_exchange_begin_blocking();
[cc574511]504 else {
[7d7f5e3]505 exch = loc_exchange_begin();
[cc574511]506 if (exch == NULL)
507 return errno;
508 }
[a35b458]509
[cc574511]510 ipc_call_t answer;
511 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
512 &answer);
[b7fd2a0]513 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]514
[cc574511]515 loc_exchange_end(exch);
[a35b458]516
[cc574511]517 if (retval != EOK) {
[50b581d]518 async_forget(req);
[cc574511]519 return retval;
520 }
[a35b458]521
[cc574511]522 async_wait_for(req, &retval);
[a35b458]523
[cc574511]524 if (retval != EOK) {
525 if (cat_id != NULL)
526 *cat_id = (category_id_t) -1;
[a35b458]527
[cc574511]528 return retval;
529 }
[a35b458]530
[cc574511]531 if (cat_id != NULL)
[fafb8e5]532 *cat_id = (category_id_t) ipc_get_arg1(&answer);
[a35b458]533
[cc574511]534 return retval;
535}
536
[15f3c3f]537loc_object_type_t loc_id_probe(service_id_t handle)
538{
[7d7f5e3]539 async_exch_t *exch = loc_exchange_begin_blocking();
[a35b458]540
[15f3c3f]541 sysarg_t type;
[b7fd2a0]542 errno_t retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
[a35b458]543
[15f3c3f]544 loc_exchange_end(exch);
[a35b458]545
[15f3c3f]546 if (retval != EOK)
547 return LOC_OBJECT_NONE;
[a35b458]548
[15f3c3f]549 return (loc_object_type_t) type;
550}
551
[f9b2cb4c]552async_sess_t *loc_service_connect(service_id_t handle, iface_t iface,
[15f3c3f]553 unsigned int flags)
554{
555 async_sess_t *sess;
[a35b458]556
[15f3c3f]557 if (flags & IPC_FLAG_BLOCKING)
[01900b6]558 sess = service_connect_blocking(SERVICE_LOC, iface, handle, NULL);
[15f3c3f]559 else
[01900b6]560 sess = service_connect(SERVICE_LOC, iface, handle, NULL);
[a35b458]561
[15f3c3f]562 return sess;
563}
564
[d5c1051]565/**
566 * @return ID of a new NULL device, or -1 if failed.
567 */
[15f3c3f]568int loc_null_create(void)
569{
[7d7f5e3]570 async_exch_t *exch = loc_exchange_begin_blocking();
[a35b458]571
[15f3c3f]572 sysarg_t null_id;
[b7fd2a0]573 errno_t retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
[a35b458]574
[15f3c3f]575 loc_exchange_end(exch);
[a35b458]576
[15f3c3f]577 if (retval != EOK)
578 return -1;
[a35b458]579
[15f3c3f]580 return (int) null_id;
581}
582
583void loc_null_destroy(int null_id)
584{
[7d7f5e3]585 async_exch_t *exch = loc_exchange_begin_blocking();
[15f3c3f]586 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
587 loc_exchange_end(exch);
588}
589
590static size_t loc_count_namespaces_internal(async_exch_t *exch)
591{
592 sysarg_t count;
[b7fd2a0]593 errno_t retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
[15f3c3f]594 if (retval != EOK)
595 return 0;
[a35b458]596
[15f3c3f]597 return count;
598}
599
[cc574511]600/** Add service to category.
601 *
[4c6fd56]602 * @param srv Server object
603 * @param svc_id Service ID
604 * @param cat_id Category ID
605 *
606 * @return EOK on success or an error code
[cc574511]607 */
[4c6fd56]608errno_t loc_service_add_to_cat(loc_srv_t *srv, service_id_t svc_id,
609 service_id_t cat_id)
[cc574511]610{
611 async_exch_t *exch;
[b7fd2a0]612 errno_t retval;
[a35b458]613
[7d7f5e3]614 exch = async_exchange_begin(srv->sess);
[cc574511]615 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
[7d7f5e3]616 async_exchange_end(exch);
[a35b458]617
[cc574511]618 return retval;
619}
620
[15f3c3f]621static size_t loc_count_services_internal(async_exch_t *exch,
622 service_id_t ns_handle)
623{
624 sysarg_t count;
[b7fd2a0]625 errno_t retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
[15f3c3f]626 &count);
627 if (retval != EOK)
628 return 0;
[a35b458]629
[15f3c3f]630 return count;
631}
632
633size_t loc_count_namespaces(void)
634{
[7d7f5e3]635 async_exch_t *exch = loc_exchange_begin_blocking();
[15f3c3f]636 size_t size = loc_count_namespaces_internal(exch);
637 loc_exchange_end(exch);
[a35b458]638
[15f3c3f]639 return size;
640}
641
642size_t loc_count_services(service_id_t ns_handle)
643{
[7d7f5e3]644 async_exch_t *exch = loc_exchange_begin_blocking();
[15f3c3f]645 size_t size = loc_count_services_internal(exch, ns_handle);
646 loc_exchange_end(exch);
[a35b458]647
[15f3c3f]648 return size;
649}
650
651size_t loc_get_namespaces(loc_sdesc_t **data)
652{
[cc574511]653 /* Loop until read is succesful */
[15f3c3f]654 while (true) {
[7d7f5e3]655 async_exch_t *exch = loc_exchange_begin_blocking();
[15f3c3f]656 size_t count = loc_count_namespaces_internal(exch);
657 loc_exchange_end(exch);
[a35b458]658
[15f3c3f]659 if (count == 0)
660 return 0;
[a35b458]661
[15f3c3f]662 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
663 if (devs == NULL)
664 return 0;
[a35b458]665
[7d7f5e3]666 exch = loc_exchange_begin();
[a35b458]667
[15f3c3f]668 ipc_call_t answer;
669 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
[b7fd2a0]670 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
[a35b458]671
[15f3c3f]672 loc_exchange_end(exch);
[a35b458]673
[15f3c3f]674 if (rc == EOVERFLOW) {
675 /*
676 * Number of namespaces has changed since
677 * the last call of LOC_GET_NAMESPACE_COUNT
678 */
679 free(devs);
680 continue;
681 }
[a35b458]682
[15f3c3f]683 if (rc != EOK) {
[50b581d]684 async_forget(req);
[15f3c3f]685 free(devs);
686 return 0;
687 }
[a35b458]688
[b7fd2a0]689 errno_t retval;
[15f3c3f]690 async_wait_for(req, &retval);
[a35b458]691
[15f3c3f]692 if (retval != EOK)
693 return 0;
[a35b458]694
[15f3c3f]695 *data = devs;
696 return count;
697 }
698}
699
700size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
701{
[cc574511]702 /* Loop until read is succesful */
[15f3c3f]703 while (true) {
[7d7f5e3]704 async_exch_t *exch = loc_exchange_begin_blocking();
[15f3c3f]705 size_t count = loc_count_services_internal(exch, ns_handle);
706 loc_exchange_end(exch);
[a35b458]707
[15f3c3f]708 if (count == 0)
709 return 0;
[a35b458]710
[15f3c3f]711 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
712 if (devs == NULL)
713 return 0;
[a35b458]714
[7d7f5e3]715 exch = loc_exchange_begin();
[a35b458]716
[15f3c3f]717 ipc_call_t answer;
718 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
[b7fd2a0]719 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
[a35b458]720
[15f3c3f]721 loc_exchange_end(exch);
[a35b458]722
[15f3c3f]723 if (rc == EOVERFLOW) {
724 /*
725 * Number of services has changed since
726 * the last call of LOC_GET_SERVICE_COUNT
727 */
728 free(devs);
729 continue;
730 }
[a35b458]731
[15f3c3f]732 if (rc != EOK) {
[50b581d]733 async_forget(req);
[15f3c3f]734 free(devs);
735 return 0;
736 }
[a35b458]737
[b7fd2a0]738 errno_t retval;
[15f3c3f]739 async_wait_for(req, &retval);
[a35b458]740
[15f3c3f]741 if (retval != EOK)
742 return 0;
[a35b458]743
[15f3c3f]744 *data = devs;
745 return count;
746 }
747}
[cc574511]748
[b7fd2a0]749static errno_t loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
[278ac72]750 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
[cc574511]751{
[7d7f5e3]752 async_exch_t *exch = loc_exchange_begin_blocking();
[cc574511]753
754 ipc_call_t answer;
[278ac72]755 aid_t req = async_send_1(exch, method, arg1, &answer);
[b7fd2a0]756 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
[a35b458]757
[cc574511]758 loc_exchange_end(exch);
[a35b458]759
[cc574511]760 if (rc != EOK) {
[50b581d]761 async_forget(req);
[cc574511]762 return rc;
763 }
[a35b458]764
[b7fd2a0]765 errno_t retval;
[cc574511]766 async_wait_for(req, &retval);
[a35b458]767
[cc574511]768 if (retval != EOK) {
769 return retval;
770 }
[a35b458]771
[fafb8e5]772 *act_size = ipc_get_arg1(&answer);
[cc574511]773 return EOK;
774}
775
[278ac72]776/** Get list of IDs.
[cc574511]777 *
778 * Returns an allocated array of service IDs.
779 *
[278ac72]780 * @param method IPC method
781 * @param arg1 IPC argument 1
[cc574511]782 * @param data Place to store pointer to array of IDs
783 * @param count Place to store number of IDs
[cde999a]784 * @return EOK on success or an error code
[cc574511]785 */
[b7fd2a0]786static errno_t loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
[278ac72]787 sysarg_t **data, size_t *count)
[cc574511]788{
789 *data = NULL;
[88057e3]790 *count = 0;
[a35b458]791
[88057e3]792 size_t act_size = 0;
[b7fd2a0]793 errno_t rc = loc_category_get_ids_once(method, arg1, NULL, 0,
[278ac72]794 &act_size);
[cc574511]795 if (rc != EOK)
796 return rc;
[a35b458]797
[88057e3]798 size_t alloc_size = act_size;
799 service_id_t *ids = malloc(alloc_size);
[cc574511]800 if (ids == NULL)
801 return ENOMEM;
[a35b458]802
[cc574511]803 while (true) {
[278ac72]804 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
[cc574511]805 &act_size);
806 if (rc != EOK)
807 return rc;
[a35b458]808
[c1f27f1d]809 if (act_size <= alloc_size)
[cc574511]810 break;
[a35b458]811
[88057e3]812 alloc_size = act_size;
[2a09dcb]813 service_id_t *tmp = realloc(ids, alloc_size);
814 if (tmp == NULL) {
815 free(ids);
[cc574511]816 return ENOMEM;
[2a09dcb]817 }
818 ids = tmp;
[cc574511]819 }
[a35b458]820
[cc574511]821 *count = act_size / sizeof(category_id_t);
822 *data = ids;
823 return EOK;
824}
[278ac72]825
826/** Get list of services in category.
827 *
828 * Returns an allocated array of service IDs.
829 *
830 * @param cat_id Category ID
831 * @param data Place to store pointer to array of IDs
832 * @param count Place to store number of IDs
[cde999a]833 * @return EOK on success or an error code
[278ac72]834 */
[b7fd2a0]835errno_t loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
[278ac72]836 size_t *count)
837{
838 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
839 data, count);
840}
841
842/** Get list of categories.
843 *
844 * Returns an allocated array of category IDs.
845 *
846 * @param data Place to store pointer to array of IDs
847 * @param count Place to store number of IDs
[cde999a]848 * @return EOK on success or an error code
[278ac72]849 */
[b7fd2a0]850errno_t loc_get_categories(category_id_t **data, size_t *count)
[278ac72]851{
852 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
853 data, count);
854}
[12f9f0d0]855
[e89a06a]856errno_t loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun, void *cb_arg)
[12f9f0d0]857{
[a6240a31]858 fibril_mutex_lock(&loc_callback_mutex);
[e89a06a]859 if (cat_change_cb != NULL) {
860 fibril_mutex_unlock(&loc_callback_mutex);
861 return EEXIST;
862 }
863
[a6240a31]864 if (loc_callback_create() != EOK) {
865 fibril_mutex_unlock(&loc_callback_mutex);
[12f9f0d0]866 return EIO;
[a6240a31]867 }
[a35b458]868
[12f9f0d0]869 cat_change_cb = cb_fun;
[e89a06a]870 cat_change_arg = cb_arg;
[a6240a31]871 fibril_mutex_unlock(&loc_callback_mutex);
[a35b458]872
[12f9f0d0]873 return EOK;
874}
Note: See TracBrowser for help on using the repository browser.