source: mainline/uspace/lib/c/generic/loc.c@ 8a74512

Last change on this file since 8a74512 was 7fa8589, checked in by Matthieu Riolo <matthieu.riolo@…>, 5 years ago

Removing unneeded casts from errno_t to errno_t

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