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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a1347a7 was f302586, checked in by Martin Decky <martin@…>, 13 years ago

make sure the client_connection is explicitly set at most once
it is not a mutable variable, it is a weak symbol

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