source: mainline/uspace/lib/c/generic/loc.c@ 5c38838

Last change on this file since 5c38838 was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 19.9 KB
Line 
1/*
2 * Copyright (c) 2007 Josef Cejka
3 * Copyright (c) 2011 Jiri Svoboda
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 <stdlib.h>
39#include <stdbool.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
47static FIBRIL_MUTEX_INITIALIZE(loc_callback_mutex);
48static bool loc_callback_created = false;
49static loc_cat_change_cb_t cat_change_cb = NULL;
50static void *cat_change_arg = NULL;
51
52static async_sess_t *loc_supp_block_sess = NULL;
53static async_sess_t *loc_cons_block_sess = NULL;
54
55static async_sess_t *loc_supplier_sess = NULL;
56static async_sess_t *loc_consumer_sess = NULL;
57
58static void loc_cb_conn(ipc_call_t *icall, void *arg)
59{
60 while (true) {
61 ipc_call_t call;
62 async_get_call(&call);
63
64 if (!IPC_GET_IMETHOD(call)) {
65 /* TODO: Handle hangup */
66 return;
67 }
68
69 switch (IPC_GET_IMETHOD(call)) {
70 case LOC_EVENT_CAT_CHANGE:
71 fibril_mutex_lock(&loc_callback_mutex);
72 loc_cat_change_cb_t cb_fun = cat_change_cb;
73 void *cb_arg = cat_change_arg;
74 fibril_mutex_unlock(&loc_callback_mutex);
75
76 async_answer_0(&call, EOK);
77
78 if (cb_fun != NULL)
79 (*cb_fun)(cb_arg);
80
81 break;
82 default:
83 async_answer_0(&call, ENOTSUP);
84 }
85 }
86}
87
88static void clone_session(fibril_mutex_t *mtx, async_sess_t *src,
89 async_sess_t **dst)
90{
91 fibril_mutex_lock(mtx);
92
93 if ((*dst == NULL) && (src != NULL))
94 *dst = src;
95
96 fibril_mutex_unlock(mtx);
97}
98
99/** Create callback
100 *
101 * Must be called with loc_callback_mutex locked.
102 *
103 * @return EOK on success.
104 *
105 */
106static errno_t loc_callback_create(void)
107{
108 if (!loc_callback_created) {
109 async_exch_t *exch =
110 loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
111
112 ipc_call_t answer;
113 aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
114
115 port_id_t port;
116 errno_t rc = async_create_callback_port(exch, INTERFACE_LOC_CB, 0, 0,
117 loc_cb_conn, NULL, &port);
118
119 loc_exchange_end(exch);
120
121 if (rc != EOK)
122 return rc;
123
124 errno_t retval;
125 async_wait_for(req, &retval);
126 if (retval != EOK)
127 return retval;
128
129 loc_callback_created = true;
130 }
131
132 return EOK;
133}
134
135/** Start an async exchange on the loc session (blocking).
136 *
137 * @param iface Location service interface to choose
138 *
139 * @return New exchange.
140 *
141 */
142async_exch_t *loc_exchange_begin_blocking(iface_t iface)
143{
144 switch (iface) {
145 case INTERFACE_LOC_SUPPLIER:
146 fibril_mutex_lock(&loc_supp_block_mutex);
147
148 while (loc_supp_block_sess == NULL) {
149 clone_session(&loc_supplier_mutex, loc_supplier_sess,
150 &loc_supp_block_sess);
151
152 if (loc_supp_block_sess == NULL)
153 loc_supp_block_sess =
154 service_connect_blocking(SERVICE_LOC,
155 INTERFACE_LOC_SUPPLIER, 0);
156 }
157
158 fibril_mutex_unlock(&loc_supp_block_mutex);
159
160 clone_session(&loc_supplier_mutex, loc_supp_block_sess,
161 &loc_supplier_sess);
162
163 return async_exchange_begin(loc_supp_block_sess);
164 case INTERFACE_LOC_CONSUMER:
165 fibril_mutex_lock(&loc_cons_block_mutex);
166
167 while (loc_cons_block_sess == NULL) {
168 clone_session(&loc_consumer_mutex, loc_consumer_sess,
169 &loc_cons_block_sess);
170
171 if (loc_cons_block_sess == NULL)
172 loc_cons_block_sess =
173 service_connect_blocking(SERVICE_LOC,
174 INTERFACE_LOC_CONSUMER, 0);
175 }
176
177 fibril_mutex_unlock(&loc_cons_block_mutex);
178
179 clone_session(&loc_consumer_mutex, loc_cons_block_sess,
180 &loc_consumer_sess);
181
182 return async_exchange_begin(loc_cons_block_sess);
183 default:
184 return NULL;
185 }
186}
187
188/** Start an async exchange on the loc session.
189 *
190 * @param iface Location service interface to choose
191 *
192 * @return New exchange.
193 *
194 */
195async_exch_t *loc_exchange_begin(iface_t iface)
196{
197 switch (iface) {
198 case INTERFACE_LOC_SUPPLIER:
199 fibril_mutex_lock(&loc_supplier_mutex);
200
201 if (loc_supplier_sess == NULL)
202 loc_supplier_sess =
203 service_connect(SERVICE_LOC,
204 INTERFACE_LOC_SUPPLIER, 0);
205
206 fibril_mutex_unlock(&loc_supplier_mutex);
207
208 if (loc_supplier_sess == NULL)
209 return NULL;
210
211 return async_exchange_begin(loc_supplier_sess);
212 case INTERFACE_LOC_CONSUMER:
213 fibril_mutex_lock(&loc_consumer_mutex);
214
215 if (loc_consumer_sess == NULL)
216 loc_consumer_sess =
217 service_connect(SERVICE_LOC,
218 INTERFACE_LOC_CONSUMER, 0);
219
220 fibril_mutex_unlock(&loc_consumer_mutex);
221
222 if (loc_consumer_sess == NULL)
223 return NULL;
224
225 return async_exchange_begin(loc_consumer_sess);
226 default:
227 return NULL;
228 }
229}
230
231/** Finish an async exchange on the loc session.
232 *
233 * @param exch Exchange to be finished.
234 *
235 */
236void loc_exchange_end(async_exch_t *exch)
237{
238 async_exchange_end(exch);
239}
240
241/** Register new driver with loc. */
242errno_t loc_server_register(const char *name)
243{
244 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
245
246 ipc_call_t answer;
247 aid_t req = async_send_2(exch, LOC_SERVER_REGISTER, 0, 0, &answer);
248 errno_t retval = async_data_write_start(exch, name, str_size(name));
249
250 if (retval != EOK) {
251 async_forget(req);
252 loc_exchange_end(exch);
253 return retval;
254 }
255
256 async_connect_to_me(exch, INTERFACE_ANY, 0, 0);
257
258 /*
259 * First wait for the answer and then end the exchange. The opposite
260 * order is generally wrong because it may lead to a deadlock under
261 * certain circumstances.
262 */
263 async_wait_for(req, &retval);
264 loc_exchange_end(exch);
265
266 return retval;
267}
268
269/** Register new service.
270 *
271 * @param fqsn Fully qualified service name
272 * @param[out] sid Service ID of new service
273 *
274 */
275errno_t loc_service_register(const char *fqsn, service_id_t *sid)
276{
277 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
278
279 ipc_call_t answer;
280 aid_t req = async_send_0(exch, LOC_SERVICE_REGISTER, &answer);
281 errno_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
282
283 if (retval != EOK) {
284 async_forget(req);
285 loc_exchange_end(exch);
286 return retval;
287 }
288
289 /*
290 * First wait for the answer and then end the exchange. The opposite
291 * order is generally wrong because it may lead to a deadlock under
292 * certain circumstances.
293 */
294 async_wait_for(req, &retval);
295 loc_exchange_end(exch);
296
297 if (retval != EOK) {
298 if (sid != NULL)
299 *sid = -1;
300
301 return retval;
302 }
303
304 if (sid != NULL)
305 *sid = (service_id_t) IPC_GET_ARG1(answer);
306
307 return retval;
308}
309
310/** Unregister service.
311 *
312 * @param sid Service ID
313 */
314errno_t loc_service_unregister(service_id_t sid)
315{
316 async_exch_t *exch;
317 errno_t retval;
318
319 exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
320 retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
321 loc_exchange_end(exch);
322
323 return (errno_t)retval;
324}
325
326errno_t loc_service_get_id(const char *fqdn, service_id_t *handle,
327 unsigned int flags)
328{
329 async_exch_t *exch;
330
331 if (flags & IPC_FLAG_BLOCKING)
332 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
333 else {
334 exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
335 if (exch == NULL)
336 return errno;
337 }
338
339 ipc_call_t answer;
340 aid_t req = async_send_2(exch, LOC_SERVICE_GET_ID, flags, 0,
341 &answer);
342 errno_t retval = async_data_write_start(exch, fqdn, str_size(fqdn));
343
344 loc_exchange_end(exch);
345
346 if (retval != EOK) {
347 async_forget(req);
348 return retval;
349 }
350
351 async_wait_for(req, &retval);
352
353 if (retval != EOK) {
354 if (handle != NULL)
355 *handle = (service_id_t) -1;
356
357 return retval;
358 }
359
360 if (handle != NULL)
361 *handle = (service_id_t) IPC_GET_ARG1(answer);
362
363 return retval;
364}
365
366/** Get object name.
367 *
368 * Provided ID of an object, return its name.
369 *
370 * @param method IPC method
371 * @param id Object ID
372 * @param name Place to store pointer to new string. Caller should
373 * free it using free().
374 * @return EOK on success or an error code
375 */
376static errno_t loc_get_name_internal(sysarg_t method, sysarg_t id, char **name)
377{
378 async_exch_t *exch;
379 char name_buf[LOC_NAME_MAXLEN + 1];
380 ipc_call_t dreply;
381 size_t act_size;
382 errno_t dretval;
383
384 *name = NULL;
385 exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
386
387 ipc_call_t answer;
388 aid_t req = async_send_1(exch, method, id, &answer);
389 aid_t dreq = async_data_read(exch, name_buf, LOC_NAME_MAXLEN,
390 &dreply);
391 async_wait_for(dreq, &dretval);
392
393 loc_exchange_end(exch);
394
395 if (dretval != EOK) {
396 async_forget(req);
397 return dretval;
398 }
399
400 errno_t retval;
401 async_wait_for(req, &retval);
402
403 if (retval != EOK)
404 return retval;
405
406 act_size = IPC_GET_ARG2(dreply);
407 assert(act_size <= LOC_NAME_MAXLEN);
408 name_buf[act_size] = '\0';
409
410 *name = str_dup(name_buf);
411 if (*name == NULL)
412 return ENOMEM;
413
414 return EOK;
415}
416
417/** Get category name.
418 *
419 * Provided ID of a service, return its name.
420 *
421 * @param cat_id Category ID
422 * @param name Place to store pointer to new string. Caller should
423 * free it using free().
424 * @return EOK on success or an error code
425 */
426errno_t loc_category_get_name(category_id_t cat_id, char **name)
427{
428 return loc_get_name_internal(LOC_CATEGORY_GET_NAME, cat_id, name);
429}
430
431/** Get service name.
432 *
433 * Provided ID of a service, return its name.
434 *
435 * @param svc_id Service ID
436 * @param name Place to store pointer to new string. Caller should
437 * free it using free().
438 * @return EOK on success or an error code
439 */
440errno_t loc_service_get_name(service_id_t svc_id, char **name)
441{
442 return loc_get_name_internal(LOC_SERVICE_GET_NAME, svc_id, name);
443}
444
445/** Get service server name.
446 *
447 * Provided ID of a service, return the name of its server.
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 an error code
453 */
454errno_t loc_service_get_server_name(service_id_t svc_id, char **name)
455{
456 return loc_get_name_internal(LOC_SERVICE_GET_SERVER_NAME, svc_id, name);
457}
458
459errno_t 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(INTERFACE_LOC_CONSUMER);
466 else {
467 exch = loc_exchange_begin(INTERFACE_LOC_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 errno_t retval = async_data_write_start(exch, name, str_size(name));
476
477 loc_exchange_end(exch);
478
479 if (retval != EOK) {
480 async_forget(req);
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
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 an error code
507 */
508errno_t 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(INTERFACE_LOC_CONSUMER);
515 else {
516 exch = loc_exchange_begin(INTERFACE_LOC_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 errno_t retval = async_data_write_start(exch, name, str_size(name));
525
526 loc_exchange_end(exch);
527
528 if (retval != EOK) {
529 async_forget(req);
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
548loc_object_type_t loc_id_probe(service_id_t handle)
549{
550 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
551
552 sysarg_t type;
553 errno_t retval = async_req_1_1(exch, LOC_ID_PROBE, handle, &type);
554
555 loc_exchange_end(exch);
556
557 if (retval != EOK)
558 return LOC_OBJECT_NONE;
559
560 return (loc_object_type_t) type;
561}
562
563async_sess_t *loc_service_connect(service_id_t handle, iface_t iface,
564 unsigned int flags)
565{
566 async_sess_t *sess;
567
568 if (flags & IPC_FLAG_BLOCKING)
569 sess = service_connect_blocking(SERVICE_LOC, iface, handle);
570 else
571 sess = service_connect(SERVICE_LOC, iface, handle);
572
573 return sess;
574}
575
576/**
577 * @return ID of a new NULL device, or -1 if failed.
578 */
579int loc_null_create(void)
580{
581 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
582
583 sysarg_t null_id;
584 errno_t 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(INTERFACE_LOC_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 errno_t retval = async_req_0_1(exch, LOC_GET_NAMESPACE_COUNT, &count);
605 if (retval != EOK)
606 return 0;
607
608 return count;
609}
610
611/** Add service to category.
612 *
613 * @param svc_id Service ID
614 * @param cat_id Category ID
615 * @return EOK on success or an error code
616 */
617errno_t loc_service_add_to_cat(service_id_t svc_id, service_id_t cat_id)
618{
619 async_exch_t *exch;
620 errno_t retval;
621
622 exch = loc_exchange_begin_blocking(INTERFACE_LOC_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
629static size_t loc_count_services_internal(async_exch_t *exch,
630 service_id_t ns_handle)
631{
632 sysarg_t count;
633 errno_t 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(INTERFACE_LOC_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(INTERFACE_LOC_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{
661 /* Loop until read is succesful */
662 while (true) {
663 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_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(INTERFACE_LOC_CONSUMER);
675
676 ipc_call_t answer;
677 aid_t req = async_send_0(exch, LOC_GET_NAMESPACES, &answer);
678 errno_t 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_forget(req);
693 free(devs);
694 return 0;
695 }
696
697 errno_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{
710 /* Loop until read is succesful */
711 while (true) {
712 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_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(INTERFACE_LOC_CONSUMER);
724
725 ipc_call_t answer;
726 aid_t req = async_send_1(exch, LOC_GET_SERVICES, ns_handle, &answer);
727 errno_t 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_forget(req);
742 free(devs);
743 return 0;
744 }
745
746 errno_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}
756
757static errno_t loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
758 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
759{
760 async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
761
762 ipc_call_t answer;
763 aid_t req = async_send_1(exch, method, arg1, &answer);
764 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
765
766 loc_exchange_end(exch);
767
768 if (rc != EOK) {
769 async_forget(req);
770 return rc;
771 }
772
773 errno_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
784/** Get list of IDs.
785 *
786 * Returns an allocated array of service IDs.
787 *
788 * @param method IPC method
789 * @param arg1 IPC argument 1
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 an error code
793 */
794static errno_t loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
795 sysarg_t **data, size_t *count)
796{
797 *data = NULL;
798 *count = 0;
799
800 size_t act_size = 0;
801 errno_t rc = loc_category_get_ids_once(method, arg1, NULL, 0,
802 &act_size);
803 if (rc != EOK)
804 return rc;
805
806 size_t alloc_size = act_size;
807 service_id_t *ids = malloc(alloc_size);
808 if (ids == NULL)
809 return ENOMEM;
810
811 while (true) {
812 rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
813 &act_size);
814 if (rc != EOK)
815 return rc;
816
817 if (act_size <= alloc_size)
818 break;
819
820 alloc_size = act_size;
821 ids = realloc(ids, alloc_size);
822 if (ids == NULL)
823 return ENOMEM;
824 }
825
826 *count = act_size / sizeof(category_id_t);
827 *data = ids;
828 return EOK;
829}
830
831/** Get list of services in category.
832 *
833 * Returns an allocated array of service IDs.
834 *
835 * @param cat_id Category ID
836 * @param data Place to store pointer to array of IDs
837 * @param count Place to store number of IDs
838 * @return EOK on success or an error code
839 */
840errno_t loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
841 size_t *count)
842{
843 return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
844 data, count);
845}
846
847/** Get list of categories.
848 *
849 * Returns an allocated array of category IDs.
850 *
851 * @param data Place to store pointer to array of IDs
852 * @param count Place to store number of IDs
853 * @return EOK on success or an error code
854 */
855errno_t loc_get_categories(category_id_t **data, size_t *count)
856{
857 return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
858 data, count);
859}
860
861errno_t loc_register_cat_change_cb(loc_cat_change_cb_t cb_fun, void *cb_arg)
862{
863 fibril_mutex_lock(&loc_callback_mutex);
864 if (cat_change_cb != NULL) {
865 fibril_mutex_unlock(&loc_callback_mutex);
866 return EEXIST;
867 }
868
869 if (loc_callback_create() != EOK) {
870 fibril_mutex_unlock(&loc_callback_mutex);
871 return EIO;
872 }
873
874 cat_change_cb = cb_fun;
875 cat_change_arg = cb_arg;
876 fibril_mutex_unlock(&loc_callback_mutex);
877
878 return EOK;
879}
Note: See TracBrowser for help on using the repository browser.