source: mainline/uspace/lib/c/generic/loc.c@ f0cc1c64

Last change on this file since f0cc1c64 was ca48672, checked in by Jiri Svoboda <jiri@…>, 8 days ago

loc_service_register() needs to take a port ID argument.

  • Property mode set to 100644
File size: 19.1 KB
RevLine 
[15f3c3f]1/*
[ca48672]2 * Copyright (c) 2025 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
[ca48672]260 * @param portid ID of port providing the service
[4c6fd56]261 * @param sid Service ID of new service
[15f3c3f]262 *
263 */
[4c6fd56]264errno_t loc_service_register(loc_srv_t *srv, const char *fqsn,
[ca48672]265 port_id_t portid, service_id_t *sid)
[15f3c3f]266{
[7d7f5e3]267 async_exch_t *exch = async_exchange_begin(srv->sess);
[15f3c3f]268 ipc_call_t answer;
[ca48672]269 aid_t req = async_send_1(exch, LOC_SERVICE_REGISTER, portid, &answer);
[b7fd2a0]270 errno_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
[a35b458]271
[15f3c3f]272 if (retval != EOK) {
[50b581d]273 async_forget(req);
[7d7f5e3]274 async_exchange_end(exch);
[15f3c3f]275 return retval;
276 }
[a35b458]277
[0239846]278 /*
279 * First wait for the answer and then end the exchange. The opposite
280 * order is generally wrong because it may lead to a deadlock under
281 * certain circumstances.
282 */
[15f3c3f]283 async_wait_for(req, &retval);
[7d7f5e3]284 async_exchange_end(exch);
[a35b458]285
[15f3c3f]286 if (retval != EOK) {
[d0dd7b5]287 if (sid != NULL)
288 *sid = -1;
[a35b458]289
[15f3c3f]290 return retval;
291 }
[a35b458]292
[d0dd7b5]293 if (sid != NULL)
[fafb8e5]294 *sid = (service_id_t) ipc_get_arg1(&answer);
[a35b458]295
[15f3c3f]296 return retval;
297}
298
[d0dd7b5]299/** Unregister service.
300 *
[4c6fd56]301 * @param srv Server object
302 * @param sid Service ID
[d0dd7b5]303 */
[4c6fd56]304errno_t loc_service_unregister(loc_srv_t *srv, service_id_t sid)
[d0dd7b5]305{
306 async_exch_t *exch;
[b7fd2a0]307 errno_t retval;
[a35b458]308
[7d7f5e3]309 exch = async_exchange_begin(srv->sess);
[d0dd7b5]310 retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
[7d7f5e3]311 async_exchange_end(exch);
[a35b458]312
[b7fd2a0]313 return (errno_t)retval;
[15f3c3f]314}
315
[b7fd2a0]316errno_t loc_service_get_id(const char *fqdn, service_id_t *handle,
[15f3c3f]317 unsigned int flags)
318{
319 async_exch_t *exch;
[a35b458]320
[15f3c3f]321 if (flags & IPC_FLAG_BLOCKING)
[7d7f5e3]322 exch = loc_exchange_begin_blocking();
[15f3c3f]323 else {
[7d7f5e3]324 exch = loc_exchange_begin();
[15f3c3f]325 if (exch == NULL)
326 return errno;
327 }
[a35b458]328
[15f3c3f]329 ipc_call_t answer;
330 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
331 &answer);
[b7fd2a0]332 errno_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
[a35b458]333
[15f3c3f]334 loc_exchange_end(exch);
[a35b458]335
[15f3c3f]336 if (retval != EOK) {
[50b581d]337 async_forget(req);
[15f3c3f]338 return retval;
339 }
[a35b458]340
[15f3c3f]341 async_wait_for(req, &retval);
[a35b458]342
[15f3c3f]343 if (retval != EOK) {
344 if (handle != NULL)
345 *handle = (service_id_t) -1;
[a35b458]346
[15f3c3f]347 return retval;
348 }
[a35b458]349
[15f3c3f]350 if (handle != NULL)
[fafb8e5]351 *handle = (service_id_t) ipc_get_arg1(&answer);
[a35b458]352
[15f3c3f]353 return retval;
354}
355
[763e0cd]356/** Get object name.
[cce8a83]357 *
[763e0cd]358 * Provided ID of an object, return its name.
[cce8a83]359 *
[763e0cd]360 * @param method IPC method
361 * @param id Object ID
[cce8a83]362 * @param name Place to store pointer to new string. Caller should
363 * free it using free().
[cde999a]364 * @return EOK on success or an error code
[cce8a83]365 */
[b7fd2a0]366static errno_t loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
[cce8a83]367{
368 async_exch_t *exch;
369 char name_buf[LOC_NAME_MAXLEN + 1];
[45058baa]370 ipc_call_t dreply;
371 size_t act_size;
[b7fd2a0]372 errno_t dretval;
[a35b458]373
[cce8a83]374 *name = NULL;
[7d7f5e3]375 exch = loc_exchange_begin_blocking();
[a35b458]376
[cce8a83]377 ipc_call_t answer;
[763e0cd]378 aid_t req = async_send_1(exch, method, id, &answer);
[45058baa]379 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
380 &dreply);
381 async_wait_for(dreq, &dretval);
[a35b458]382
[cce8a83]383 loc_exchange_end(exch);
[a35b458]384
[45058baa]385 if (dretval != EOK) {
[50b581d]386 async_forget(req);
[45058baa]387 return dretval;
[cce8a83]388 }
[a35b458]389
[b7fd2a0]390 errno_t retval;
[cce8a83]391 async_wait_for(req, &retval);
[a35b458]392
[cce8a83]393 if (retval != EOK)
394 return retval;
[a35b458]395
[fafb8e5]396 act_size = ipc_get_arg2(&dreply);
[45058baa]397 assert(act_size <= LOC_NAME_MAXLEN);
398 name_buf[act_size] = '\0';
399
[cce8a83]400 *name = str_dup(name_buf);
401 if (*name == NULL)
402 return ENOMEM;
[a35b458]403
[cce8a83]404 return EOK;
405}
406
[763e0cd]407/** Get category name.
408 *
409 * Provided ID of a service, return its name.
410 *
411 * @param cat_id Category ID
412 * @param name Place to store pointer to new string. Caller should
413 * free it using free().
[cde999a]414 * @return EOK on success or an error code
[763e0cd]415 */
[b7fd2a0]416errno_t loc_category_get_name(category_id_t cat_id, char **name)
[763e0cd]417{
418 return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
419}
420
421/** Get service name.
422 *
423 * Provided ID of a service, return its name.
424 *
425 * @param svc_id Service ID
426 * @param name Place to store pointer to new string. Caller should
427 * free it using free().
[cde999a]428 * @return EOK on success or an error code
[763e0cd]429 */
[b7fd2a0]430errno_t loc_service_get_name(service_id_t svc_id, char **name)
[763e0cd]431{
432 return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
433}
[cce8a83]434
[a3fcfba]435/** Get service server name.
436 *
437 * Provided ID of a service, return the name of its server.
438 *
439 * @param svc_id Service ID
440 * @param name Place to store pointer to new string. Caller should
441 * free it using free().
[cde999a]442 * @return EOK on success or an error code
[a3fcfba]443 */
[b7fd2a0]444errno_t loc_service_get_server_name(service_id_t svc_id, char **name)
[a3fcfba]445{
446 return loc_get_name_internal(LOC_SERVICE_GET_SERVER_NAME, svc_id, name);
447}
448
[b7fd2a0]449errno_t loc_namespace_get_id(const char *name, service_id_t *handle,
[15f3c3f]450 unsigned int flags)
451{
452 async_exch_t *exch;
[a35b458]453
[15f3c3f]454 if (flags & IPC_FLAG_BLOCKING)
[7d7f5e3]455 exch = loc_exchange_begin_blocking();
[15f3c3f]456 else {
[7d7f5e3]457 exch = loc_exchange_begin();
[15f3c3f]458 if (exch == NULL)
459 return errno;
460 }
[a35b458]461
[15f3c3f]462 ipc_call_t answer;
463 aid_t req = async_send_2(exch, LOC_NAMESPACE_GET_ID, flags, 0,
464 &answer);
[b7fd2a0]465 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]466
[15f3c3f]467 loc_exchange_end(exch);
[a35b458]468
[15f3c3f]469 if (retval != EOK) {
[50b581d]470 async_forget(req);
[15f3c3f]471 return retval;
472 }
[a35b458]473
[15f3c3f]474 async_wait_for(req, &retval);
[a35b458]475
[15f3c3f]476 if (retval != EOK) {
477 if (handle != NULL)
478 *handle = (service_id_t) -1;
[a35b458]479
[15f3c3f]480 return retval;
481 }
[a35b458]482
[15f3c3f]483 if (handle != NULL)
[fafb8e5]484 *handle = (service_id_t) ipc_get_arg1(&answer);
[a35b458]485
[15f3c3f]486 return retval;
487}
488
[cc574511]489/** Get category ID.
490 *
491 * Provided name of a category, return its ID.
492 *
493 * @param name Category name
494 * @param cat_id Place to store ID
495 * @param flags IPC_FLAG_BLOCKING to wait for location service to start
[cde999a]496 * @return EOK on success or an error code
[cc574511]497 */
[b7fd2a0]498errno_t loc_category_get_id(const char *name, category_id_t *cat_id,
[cc574511]499 unsigned int flags)
500{
501 async_exch_t *exch;
[a35b458]502
[cc574511]503 if (flags & IPC_FLAG_BLOCKING)
[7d7f5e3]504 exch = loc_exchange_begin_blocking();
[cc574511]505 else {
[7d7f5e3]506 exch = loc_exchange_begin();
[cc574511]507 if (exch == NULL)
508 return errno;
509 }
[a35b458]510
[cc574511]511 ipc_call_t answer;
512 aid_t req = async_send_0(exch, LOC_CATEGORY_GET_ID,
513 &answer);
[b7fd2a0]514 errno_t retval = async_data_write_start(exch, name, str_size(name));
[a35b458]515
[cc574511]516 loc_exchange_end(exch);
[a35b458]517
[cc574511]518 if (retval != EOK) {
[50b581d]519 async_forget(req);
[cc574511]520 return retval;
521 }
[a35b458]522
[cc574511]523 async_wait_for(req, &retval);
[a35b458]524
[cc574511]525 if (retval != EOK) {
526 if (cat_id != NULL)
527 *cat_id = (category_id_t) -1;
[a35b458]528
[cc574511]529 return retval;
530 }
[a35b458]531
[cc574511]532 if (cat_id != NULL)
[fafb8e5]533 *cat_id = (category_id_t) ipc_get_arg1(&answer);
[a35b458]534
[cc574511]535 return retval;
536}
537
[15f3c3f]538loc_object_type_t loc_id_probe(service_id_t handle)
539{
[7d7f5e3]540 async_exch_t *exch = loc_exchange_begin_blocking();
[a35b458]541
[15f3c3f]542 sysarg_t type;
[b7fd2a0]543 errno_t retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
[a35b458]544
[15f3c3f]545 loc_exchange_end(exch);
[a35b458]546
[15f3c3f]547 if (retval != EOK)
548 return LOC_OBJECT_NONE;
[a35b458]549
[15f3c3f]550 return (loc_object_type_t) type;
551}
552
[f9b2cb4c]553async_sess_t *loc_service_connect(service_id_t handle, iface_t iface,
[15f3c3f]554 unsigned int flags)
555{
556 async_sess_t *sess;
[a35b458]557
[15f3c3f]558 if (flags & IPC_FLAG_BLOCKING)
[01900b6]559 sess = service_connect_blocking(SERVICE_LOC, iface, handle, NULL);
[15f3c3f]560 else
[01900b6]561 sess = service_connect(SERVICE_LOC, iface, handle, NULL);
[a35b458]562
[15f3c3f]563 return sess;
564}
565
[d5c1051]566/**
567 * @return ID of a new NULL device, or -1 if failed.
568 */
[15f3c3f]569int loc_null_create(void)
570{
[7d7f5e3]571 async_exch_t *exch = loc_exchange_begin_blocking();
[a35b458]572
[15f3c3f]573 sysarg_t null_id;
[b7fd2a0]574 errno_t retval = async_req_0_1(exch, LOC_NULL_CREATE, &null_id);
[a35b458]575
[15f3c3f]576 loc_exchange_end(exch);
[a35b458]577
[15f3c3f]578 if (retval != EOK)
579 return -1;
[a35b458]580
[15f3c3f]581 return (int) null_id;
582}
583
584void loc_null_destroy(int null_id)
585{
[7d7f5e3]586 async_exch_t *exch = loc_exchange_begin_blocking();
[15f3c3f]587 async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
588 loc_exchange_end(exch);
589}
590
591static size_t loc_count_namespaces_internal(async_exch_t *exch)
592{
593 sysarg_t count;
[b7fd2a0]594 errno_t retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
[15f3c3f]595 if (retval != EOK)
596 return 0;
[a35b458]597
[15f3c3f]598 return count;
599}
600
[cc574511]601/** Add service to category.
602 *
[4c6fd56]603 * @param srv Server object
604 * @param svc_id Service ID
605 * @param cat_id Category ID
606 *
607 * @return EOK on success or an error code
[cc574511]608 */
[4c6fd56]609errno_t loc_service_add_to_cat(loc_srv_t *srv, service_id_t svc_id,
610 service_id_t cat_id)
[cc574511]611{
612 async_exch_t *exch;
[b7fd2a0]613 errno_t retval;
[a35b458]614
[7d7f5e3]615 exch = async_exchange_begin(srv->sess);
[cc574511]616 retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
[7d7f5e3]617 async_exchange_end(exch);
[a35b458]618
[cc574511]619 return retval;
620}
621
[15f3c3f]622static size_t loc_count_services_internal(async_exch_t *exch,
623 service_id_t ns_handle)
624{
625 sysarg_t count;
[b7fd2a0]626 errno_t retval = async_req_1_1(exch, LOC_GET_SERVICE_COUNT, ns_handle,
[15f3c3f]627 &count);
628 if (retval != EOK)
629 return 0;
[a35b458]630
[15f3c3f]631 return count;
632}
633
634size_t loc_count_namespaces(void)
635{
[7d7f5e3]636 async_exch_t *exch = loc_exchange_begin_blocking();
[15f3c3f]637 size_t size = loc_count_namespaces_internal(exch);
638 loc_exchange_end(exch);
[a35b458]639
[15f3c3f]640 return size;
641}
642
643size_t loc_count_services(service_id_t ns_handle)
644{
[7d7f5e3]645 async_exch_t *exch = loc_exchange_begin_blocking();
[15f3c3f]646 size_t size = loc_count_services_internal(exch, ns_handle);
647 loc_exchange_end(exch);
[a35b458]648
[15f3c3f]649 return size;
650}
651
652size_t loc_get_namespaces(loc_sdesc_t **data)
653{
[cc574511]654 /* Loop until read is succesful */
[15f3c3f]655 while (true) {
[7d7f5e3]656 async_exch_t *exch = loc_exchange_begin_blocking();
[15f3c3f]657 size_t count = loc_count_namespaces_internal(exch);
658 loc_exchange_end(exch);
[a35b458]659
[15f3c3f]660 if (count == 0)
661 return 0;
[a35b458]662
[15f3c3f]663 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
664 if (devs == NULL)
665 return 0;
[a35b458]666
[7d7f5e3]667 exch = loc_exchange_begin();
[a35b458]668
[15f3c3f]669 ipc_call_t answer;
670 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
[b7fd2a0]671 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
[a35b458]672
[15f3c3f]673 loc_exchange_end(exch);
[a35b458]674
[15f3c3f]675 if (rc == EOVERFLOW) {
676 /*
677 * Number of namespaces has changed since
678 * the last call of LOC_GET_NAMESPACE_COUNT
679 */
680 free(devs);
681 continue;
682 }
[a35b458]683
[15f3c3f]684 if (rc != EOK) {
[50b581d]685 async_forget(req);
[15f3c3f]686 free(devs);
687 return 0;
688 }
[a35b458]689
[b7fd2a0]690 errno_t retval;
[15f3c3f]691 async_wait_for(req, &retval);
[a35b458]692
[15f3c3f]693 if (retval != EOK)
694 return 0;
[a35b458]695
[15f3c3f]696 *data = devs;
697 return count;
698 }
699}
700
701size_t loc_get_services(service_id_t ns_handle, loc_sdesc_t **data)
702{
[cc574511]703 /* Loop until read is succesful */
[15f3c3f]704 while (true) {
[7d7f5e3]705 async_exch_t *exch = loc_exchange_begin_blocking();
[15f3c3f]706 size_t count = loc_count_services_internal(exch, ns_handle);
707 loc_exchange_end(exch);
[a35b458]708
[15f3c3f]709 if (count == 0)
710 return 0;
[a35b458]711
[15f3c3f]712 loc_sdesc_t *devs = (loc_sdesc_t *) calloc(count, sizeof(loc_sdesc_t));
713 if (devs == NULL)
714 return 0;
[a35b458]715
[7d7f5e3]716 exch = loc_exchange_begin();
[a35b458]717
[15f3c3f]718 ipc_call_t answer;
719 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
[b7fd2a0]720 errno_t rc = async_data_read_start(exch, devs, count * sizeof(loc_sdesc_t));
[a35b458]721
[15f3c3f]722 loc_exchange_end(exch);
[a35b458]723
[15f3c3f]724 if (rc == EOVERFLOW) {
725 /*
726 * Number of services has changed since
727 * the last call of LOC_GET_SERVICE_COUNT
728 */
729 free(devs);
730 continue;
731 }
[a35b458]732
[15f3c3f]733 if (rc != EOK) {
[50b581d]734 async_forget(req);
[15f3c3f]735 free(devs);
736 return 0;
737 }
[a35b458]738
[b7fd2a0]739 errno_t retval;
[15f3c3f]740 async_wait_for(req, &retval);
[a35b458]741
[15f3c3f]742 if (retval != EOK)
743 return 0;
[a35b458]744
[15f3c3f]745 *data = devs;
746 return count;
747 }
748}
[cc574511]749
[b7fd2a0]750static errno_t loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
[278ac72]751 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
[cc574511]752{
[7d7f5e3]753 async_exch_t *exch = loc_exchange_begin_blocking();
[cc574511]754
755 ipc_call_t answer;
[278ac72]756 aid_t req = async_send_1(exch, method, arg1, &answer);
[b7fd2a0]757 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
[a35b458]758
[cc574511]759 loc_exchange_end(exch);
[a35b458]760
[cc574511]761 if (rc != EOK) {
[50b581d]762 async_forget(req);
[cc574511]763 return rc;
764 }
[a35b458]765
[b7fd2a0]766 errno_t retval;
[cc574511]767 async_wait_for(req, &retval);
[a35b458]768
[cc574511]769 if (retval != EOK) {
770 return retval;
771 }
[a35b458]772
[fafb8e5]773 *act_size = ipc_get_arg1(&answer);
[cc574511]774 return EOK;
775}
776
[278ac72]777/** Get list of IDs.
[cc574511]778 *
779 * Returns an allocated array of service IDs.
780 *
[278ac72]781 * @param method IPC method
782 * @param arg1 IPC argument 1
[cc574511]783 * @param data Place to store pointer to array of IDs
784 * @param count Place to store number of IDs
[cde999a]785 * @return EOK on success or an error code
[cc574511]786 */
[b7fd2a0]787static errno_t loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
[278ac72]788 sysarg_t **data, size_t *count)
[cc574511]789{
790 *data = NULL;
[88057e3]791 *count = 0;
[a35b458]792
[88057e3]793 size_t act_size = 0;
[b7fd2a0]794 errno_t rc = loc_category_get_ids_once(method, arg1, NULL, 0,
[278ac72]795 &act_size);
[cc574511]796 if (rc != EOK)
797 return rc;
[a35b458]798
[88057e3]799 size_t alloc_size = act_size;
800 service_id_t *ids = malloc(alloc_size);
[cc574511]801 if (ids == NULL)
802 return ENOMEM;
[a35b458]803
[cc574511]804 while (true) {
[278ac72]805 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
[cc574511]806 &act_size);
807 if (rc != EOK)
808 return rc;
[a35b458]809
[c1f27f1d]810 if (act_size <= alloc_size)
[cc574511]811 break;
[a35b458]812
[88057e3]813 alloc_size = act_size;
[2a09dcb]814 service_id_t *tmp = realloc(ids, alloc_size);
815 if (tmp == NULL) {
816 free(ids);
[cc574511]817 return ENOMEM;
[2a09dcb]818 }
819 ids = tmp;
[cc574511]820 }
[a35b458]821
[cc574511]822 *count = act_size / sizeof(category_id_t);
823 *data = ids;
824 return EOK;
825}
[278ac72]826
827/** Get list of services in category.
828 *
829 * Returns an allocated array of service IDs.
830 *
831 * @param cat_id Category ID
832 * @param data Place to store pointer to array of IDs
833 * @param count Place to store number of IDs
[cde999a]834 * @return EOK on success or an error code
[278ac72]835 */
[b7fd2a0]836errno_t loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
[278ac72]837 size_t *count)
838{
839 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
840 data, count);
841}
842
843/** Get list of categories.
844 *
845 * Returns an allocated array of category IDs.
846 *
847 * @param data Place to store pointer to array of IDs
848 * @param count Place to store number of IDs
[cde999a]849 * @return EOK on success or an error code
[278ac72]850 */
[b7fd2a0]851errno_t loc_get_categories(category_id_t **data, size_t *count)
[278ac72]852{
853 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
854 data, count);
855}
[12f9f0d0]856
[e89a06a]857errno_t loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun, void *cb_arg)
[12f9f0d0]858{
[a6240a31]859 fibril_mutex_lock(&loc_callback_mutex);
[e89a06a]860 if (cat_change_cb != NULL) {
861 fibril_mutex_unlock(&loc_callback_mutex);
862 return EEXIST;
863 }
864
[a6240a31]865 if (loc_callback_create() != EOK) {
866 fibril_mutex_unlock(&loc_callback_mutex);
[12f9f0d0]867 return EIO;
[a6240a31]868 }
[a35b458]869
[12f9f0d0]870 cat_change_cb = cb_fun;
[e89a06a]871 cat_change_arg = cb_arg;
[a6240a31]872 fibril_mutex_unlock(&loc_callback_mutex);
[a35b458]873
[12f9f0d0]874 return EOK;
875}
Note: See TracBrowser for help on using the repository browser.