source: mainline/uspace/srv/locsrv/locsrv.c@ 25697163

Last change on this file since 25697163 was 102f641, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

Correcting syntax according to ccheck

  • Property mode set to 100644
File size: 37.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/**
31 * @addtogroup locsrv
32 * @{
33 */
34
35/** @file
36 */
37
38#include <assert.h>
39#include <async.h>
40#include <errno.h>
41#include <ipc/loc.h>
42#include <ipc/services.h>
43#include <fibril_synch.h>
44#include <macros.h>
45#include <ns.h>
46#include <stdbool.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <str.h>
50#include <str_error.h>
51#include <sysman/broker.h>
52#include <sysman/ctl.h>
53
54#include "category.h"
55#include "locsrv.h"
56
57#define NAME "loc"
58#define NULL_SERVICES 256
59
60/** Callback session */
61typedef struct {
62 link_t cb_sess_list;
63 async_sess_t *sess;
64} cb_sess_t;
65
66typedef enum {
67 NAME_TO_START,
68 NAME_TO_EXPOSE
69} unit_name_t;
70
71LIST_INITIALIZE(services_list);
72LIST_INITIALIZE(namespaces_list);
73LIST_INITIALIZE(servers_list);
74
75/*
76 * Locking order:
77 * servers_list_mutex
78 * services_list_mutex
79 * (loc_server_t *)->services_mutex
80 * create_id_mutex
81 */
82
83FIBRIL_MUTEX_INITIALIZE(services_list_mutex);
84static FIBRIL_CONDVAR_INITIALIZE(services_list_cv);
85static FIBRIL_MUTEX_INITIALIZE(servers_list_mutex);
86static FIBRIL_MUTEX_INITIALIZE(create_id_mutex);
87static FIBRIL_MUTEX_INITIALIZE(null_services_mutex);
88
89static service_id_t last_id = 0;
90static loc_service_t *null_services[NULL_SERVICES];
91
92/*
93 * Dummy list for null services. This is necessary so that null services can
94 * be used just as any other services, e.g. in loc_service_unregister_core().
95 */
96static LIST_INITIALIZE(dummy_null_services);
97
98/** Service directory ogranized by categories (yellow pages) */
99static categ_dir_t cdir;
100
101static FIBRIL_MUTEX_INITIALIZE(callback_sess_mutex);
102static LIST_INITIALIZE(callback_sess_list);
103
104service_id_t loc_create_id(void)
105{
106 /*
107 * TODO: allow reusing old ids after their unregistration
108 * and implement some version of LRU algorithm, avoid overflow
109 */
110
111 fibril_mutex_lock(&create_id_mutex);
112 last_id++;
113 fibril_mutex_unlock(&create_id_mutex);
114
115 return last_id;
116}
117
118/** Convert fully qualified service name to namespace and service name.
119 *
120 * A fully qualified service name can be either a plain service name
121 * (then the namespace is considered to be an empty string) or consist
122 * of two components separated by a slash. No more than one slash
123 * is allowed.
124 *
125 */
126static bool loc_fqsn_split(const char *fqsn, char **ns_name, char **name)
127{
128 size_t cnt = 0;
129 size_t slash_offset = 0;
130 size_t slash_after = 0;
131
132 size_t offset = 0;
133 size_t offset_prev = 0;
134 wchar_t c;
135
136 while ((c = str_decode(fqsn, &offset, STR_NO_LIMIT)) != 0) {
137 if (c == '/') {
138 cnt++;
139 slash_offset = offset_prev;
140 slash_after = offset;
141 }
142 offset_prev = offset;
143 }
144
145 /* More than one slash */
146 if (cnt > 1)
147 return false;
148
149 /* No slash -> namespace is empty */
150 if (cnt == 0) {
151 *ns_name = str_dup("");
152 if (*ns_name == NULL)
153 return false;
154
155 *name = str_dup(fqsn);
156 if (*name == NULL) {
157 free(*ns_name);
158 return false;
159 }
160
161 if (str_cmp(*name, "") == 0) {
162 free(*name);
163 free(*ns_name);
164 return false;
165 }
166
167 return true;
168 }
169
170 /* Exactly one slash */
171 *ns_name = str_ndup(fqsn, slash_offset);
172 if (*ns_name == NULL)
173 return false;
174
175 *name = str_dup(fqsn + slash_after);
176 if (*name == NULL) {
177 free(*ns_name);
178 return false;
179 }
180
181 if (str_cmp(*name, "") == 0) {
182 free(*name);
183 free(*ns_name);
184 return false;
185 }
186
187 return true;
188}
189
190/** Find namespace with given name. */
191static loc_namespace_t *loc_namespace_find_name(const char *name)
192{
193 assert(fibril_mutex_is_locked(&services_list_mutex));
194
195 list_foreach(namespaces_list, namespaces, loc_namespace_t, namespace) {
196 if (str_cmp(namespace->name, name) == 0)
197 return namespace;
198 }
199
200 return NULL;
201}
202
203/** Find namespace with given ID.
204 *
205 * @todo: use hash table
206 *
207 */
208static loc_namespace_t *loc_namespace_find_id(service_id_t id)
209{
210 assert(fibril_mutex_is_locked(&services_list_mutex));
211
212 list_foreach(namespaces_list, namespaces, loc_namespace_t, namespace) {
213 if (namespace->id == id)
214 return namespace;
215 }
216
217 return NULL;
218}
219
220/** Find service with given name. */
221static loc_service_t *loc_service_find_name(const char *ns_name,
222 const char *name)
223{
224 assert(fibril_mutex_is_locked(&services_list_mutex));
225
226 list_foreach(services_list, services, loc_service_t, service) {
227 if ((str_cmp(service->namespace->name, ns_name) == 0) &&
228 (str_cmp(service->name, name) == 0))
229 return service;
230 }
231
232 return NULL;
233}
234
235/** Find service with given ID.
236 *
237 * @todo: use hash table
238 *
239 */
240static loc_service_t *loc_service_find_id(service_id_t id)
241{
242 assert(fibril_mutex_is_locked(&services_list_mutex));
243
244 list_foreach(services_list, services, loc_service_t, service) {
245 if (service->id == id)
246 return service;
247 }
248
249 return NULL;
250}
251
252/** Create a namespace (if not already present). */
253static loc_namespace_t *loc_namespace_create(const char *ns_name)
254{
255 loc_namespace_t *namespace;
256
257 assert(fibril_mutex_is_locked(&services_list_mutex));
258
259 namespace = loc_namespace_find_name(ns_name);
260 if (namespace != NULL)
261 return namespace;
262
263 namespace = (loc_namespace_t *) malloc(sizeof(loc_namespace_t));
264 if (namespace == NULL)
265 return NULL;
266
267 namespace->name = str_dup(ns_name);
268 if (namespace->name == NULL) {
269 free(namespace);
270 return NULL;
271 }
272
273 namespace->id = loc_create_id();
274 namespace->refcnt = 0;
275
276 /*
277 * Insert new namespace into list of registered namespaces
278 */
279 list_append(&(namespace->namespaces), &namespaces_list);
280
281 return namespace;
282}
283
284/** Destroy a namespace (if it is no longer needed). */
285static void loc_namespace_destroy(loc_namespace_t *namespace)
286{
287 assert(fibril_mutex_is_locked(&services_list_mutex));
288
289 if (namespace->refcnt == 0) {
290 list_remove(&(namespace->namespaces));
291
292 free(namespace->name);
293 free(namespace);
294 }
295}
296
297/** Increase namespace reference count by including service. */
298static void loc_namespace_addref(loc_namespace_t *namespace,
299 loc_service_t *service)
300{
301 assert(fibril_mutex_is_locked(&services_list_mutex));
302
303 service->namespace = namespace;
304 namespace->refcnt++;
305}
306
307/** Decrease namespace reference count. */
308static void loc_namespace_delref(loc_namespace_t *namespace)
309{
310 assert(fibril_mutex_is_locked(&services_list_mutex));
311
312 namespace->refcnt--;
313 loc_namespace_destroy(namespace);
314}
315
316/** Unregister service and free it. */
317static void loc_service_unregister_core(loc_service_t *service)
318{
319 assert(fibril_mutex_is_locked(&services_list_mutex));
320 assert(fibril_mutex_is_locked(&cdir.mutex));
321
322 loc_namespace_delref(service->namespace);
323 list_remove(&(service->services));
324 list_remove(&(service->server_services));
325
326 /* Remove service from all categories. */
327 while (!list_empty(&service->cat_memb)) {
328 link_t *link = list_first(&service->cat_memb);
329 svc_categ_t *memb = list_get_instance(link, svc_categ_t,
330 svc_link);
331 category_t *cat = memb->cat;
332
333 fibril_mutex_lock(&cat->mutex);
334 category_remove_service(memb);
335 fibril_mutex_unlock(&cat->mutex);
336 }
337
338 free(service->name);
339 free(service);
340}
341
342/** Derive unit name from service name according to purpose
343 *
344 * All services in 'device' namespace are considered to be drivers and
345 * devman is thus requested to start. Otherwise name of unit is made
346 * from fully qualified name of service (namespace separator is changed
347 * for usage in unit name.
348 */
349static int loc_service_unit_name(const char *ns_name, const char *name,
350 unit_name_t name_type, char **unit_name_ptr)
351{
352 char *service_name = NULL;
353 if (name_type == NAME_TO_START &&
354 str_cmp(ns_name, LOC_DEVICE_NAMESPACE) == 0) {
355 asprintf(&service_name, "%s", SERVICE_NAME_DEVMAN);
356 } else if (str_cmp(ns_name, "") == 0) {
357 asprintf(&service_name, "%s", name);
358 } else {
359 asprintf(&service_name, "%s%s%s",
360 ns_name, LOC_UNIT_NAMESPACE_SEPARATOR, name);
361 }
362 if (service_name == NULL) {
363 return ENOMEM;
364 }
365
366 char *unit_name;
367 asprintf(&unit_name, "%s%c%s",
368 service_name, UNIT_NAME_SEPARATOR, UNIT_SVC_TYPE_NAME);
369 if (unit_name == NULL) {
370 free(service_name);
371 return ENOMEM;
372 }
373
374 *unit_name_ptr = unit_name;
375 return EOK;
376}
377
378static int loc_service_request_start(const char *ns_name, const char *name)
379{
380 char *unit_name;
381 int rc = loc_service_unit_name(ns_name, name, NAME_TO_START, &unit_name);
382 if (rc != EOK) {
383 return rc;
384 }
385
386 rc = sysman_unit_start_by_name(unit_name, IPC_FLAG_BLOCKING);
387 free(unit_name);
388 return rc;
389}
390
391/**
392 * Read info about new server and add it into linked list of registered
393 * servers.
394 */
395static loc_server_t *loc_server_register(void)
396{
397 ipc_call_t icall;
398 async_get_call(&icall);
399
400 if (ipc_get_imethod(&icall) != LOC_SERVER_REGISTER) {
401 async_answer_0(&icall, EREFUSED);
402 return NULL;
403 }
404
405 loc_server_t *server =
406 (loc_server_t *) malloc(sizeof(loc_server_t));
407 if (server == NULL) {
408 async_answer_0(&icall, ENOMEM);
409 return NULL;
410 }
411
412 /*
413 * Get server name
414 */
415 errno_t rc = async_data_write_accept((void **) &server->name, true, 0,
416 LOC_NAME_MAXLEN, 0, NULL);
417 if (rc != EOK) {
418 free(server);
419 async_answer_0(&icall, rc);
420 return NULL;
421 }
422
423 /*
424 * Create connection to the server
425 */
426 server->sess = async_callback_receive(EXCHANGE_SERIALIZE);
427 if (!server->sess) {
428 free(server->name);
429 free(server);
430 async_answer_0(&icall, ENOTSUP);
431 return NULL;
432 }
433
434 /*
435 * Initialize mutex for list of services
436 * supplied by this server
437 */
438 fibril_mutex_initialize(&server->services_mutex);
439
440 /*
441 * Initialize list of supplied services
442 */
443 list_initialize(&server->services);
444 link_initialize(&server->servers);
445
446 fibril_mutex_lock(&servers_list_mutex);
447
448 /*
449 * TODO:
450 * Check that no server with name equal to
451 * server->name is registered
452 */
453
454 /*
455 * Insert new server into list of registered servers
456 */
457 list_append(&(server->servers), &servers_list);
458 fibril_mutex_unlock(&servers_list_mutex);
459
460 async_answer_0(&icall, EOK);
461
462 return server;
463}
464
465/**
466 * Unregister server, unregister all its services and free server
467 * structure.
468 *
469 */
470static errno_t loc_server_unregister(loc_server_t *server)
471{
472 if (server == NULL)
473 return EEXIST;
474
475 fibril_mutex_lock(&servers_list_mutex);
476
477 if (server->sess)
478 async_hangup(server->sess);
479
480 /* Remove it from list of servers */
481 list_remove(&(server->servers));
482
483 /* Unregister all its services */
484 fibril_mutex_lock(&services_list_mutex);
485 fibril_mutex_lock(&server->services_mutex);
486 fibril_mutex_lock(&cdir.mutex);
487
488 while (!list_empty(&server->services)) {
489 loc_service_t *service = list_get_instance(
490 list_first(&server->services), loc_service_t,
491 server_services);
492 loc_service_unregister_core(service);
493 }
494
495 fibril_mutex_unlock(&cdir.mutex);
496 fibril_mutex_unlock(&server->services_mutex);
497 fibril_mutex_unlock(&services_list_mutex);
498 fibril_mutex_unlock(&servers_list_mutex);
499
500 /* Free name and server */
501 if (server->name != NULL)
502 free(server->name);
503
504 free(server);
505
506 loc_category_change_event();
507 return EOK;
508}
509
510/** Register service
511 *
512 */
513static void loc_service_register(ipc_call_t *icall, loc_server_t *server)
514{
515 if (server == NULL) {
516 async_answer_0(icall, EREFUSED);
517 return;
518 }
519
520 /* Create new service entry */
521 loc_service_t *service =
522 (loc_service_t *) malloc(sizeof(loc_service_t));
523 if (service == NULL) {
524 async_answer_0(icall, ENOMEM);
525 return;
526 }
527
528 /* Get fqsn */
529 char *fqsn;
530 errno_t rc = async_data_write_accept((void **) &fqsn, true, 0,
531 LOC_NAME_MAXLEN, 0, NULL);
532 if (rc != EOK) {
533 free(service);
534 async_answer_0(icall, rc);
535 return;
536 }
537
538 char *ns_name;
539 if (!loc_fqsn_split(fqsn, &ns_name, &service->name)) {
540 free(fqsn);
541 free(service);
542 async_answer_0(icall, EINVAL);
543 return;
544 }
545
546 free(fqsn);
547
548 fibril_mutex_lock(&services_list_mutex);
549
550 loc_namespace_t *namespace = loc_namespace_create(ns_name);
551 free(ns_name);
552 if (namespace == NULL) {
553 fibril_mutex_unlock(&services_list_mutex);
554 free(service->name);
555 free(service);
556 async_answer_0(icall, ENOMEM);
557 return;
558 }
559
560 link_initialize(&service->services);
561 link_initialize(&service->server_services);
562 list_initialize(&service->cat_memb);
563
564 /* Check that service is not already registered */
565 if (loc_service_find_name(namespace->name, service->name) != NULL) {
566 printf("%s: Service '%s/%s' already registered\n", NAME,
567 namespace->name, service->name);
568 loc_namespace_destroy(namespace);
569 fibril_mutex_unlock(&services_list_mutex);
570 free(service->name);
571 free(service);
572 async_answer_0(icall, EEXIST);
573 return;
574 }
575
576 /* Notify sysman about new exposee */
577 char *unit_name = NULL;
578 rc = loc_service_unit_name(namespace->name, service->name,
579 NAME_TO_EXPOSE, &unit_name);
580 if (rc != EOK) {
581 loc_namespace_destroy(namespace);
582 fibril_mutex_unlock(&services_list_mutex);
583 free(service->name);
584 free(service);
585 free(unit_name);
586 async_answer_0(icall, rc);
587 return;
588 }
589
590 if (str_cmp(namespace->name, LOC_DEVICE_NAMESPACE) == 0) {
591 sysman_exposee_added(unit_name);
592 } else {
593 sysman_main_exposee_added(unit_name, icall->task_id);
594 }
595 free(unit_name);
596
597 /* Get unique service ID */
598 service->id = loc_create_id();
599
600 loc_namespace_addref(namespace, service);
601 service->server = server;
602
603 /* Insert service into list of all services */
604 list_append(&service->services, &services_list);
605
606 /* Insert service into list of services supplied by one server */
607 fibril_mutex_lock(&service->server->services_mutex);
608
609 list_append(&service->server_services, &service->server->services);
610
611 fibril_mutex_unlock(&service->server->services_mutex);
612 fibril_condvar_broadcast(&services_list_cv);
613 fibril_mutex_unlock(&services_list_mutex);
614
615 async_answer_1(icall, EOK, service->id);
616}
617
618/**
619 *
620 */
621static void loc_service_unregister(ipc_call_t *icall, loc_server_t *server)
622{
623 loc_service_t *svc;
624
625 fibril_mutex_lock(&services_list_mutex);
626 svc = loc_service_find_id(ipc_get_arg1(icall));
627 if (svc == NULL) {
628 fibril_mutex_unlock(&services_list_mutex);
629 async_answer_0(icall, ENOENT);
630 return;
631 }
632
633 fibril_mutex_lock(&cdir.mutex);
634 loc_service_unregister_core(svc);
635 fibril_mutex_unlock(&cdir.mutex);
636 fibril_mutex_unlock(&services_list_mutex);
637
638 /*
639 * First send out all notifications and only then answer the request.
640 * Otherwise the current fibril might block and transitively wait for
641 * the completion of requests that are routed to it via an IPC loop.
642 */
643 loc_category_change_event();
644 async_answer_0(icall, EOK);
645}
646
647static void loc_category_get_name(ipc_call_t *icall)
648{
649 ipc_call_t call;
650 size_t size;
651 size_t act_size;
652 category_t *cat;
653
654 if (!async_data_read_receive(&call, &size)) {
655 async_answer_0(&call, EREFUSED);
656 async_answer_0(icall, EREFUSED);
657 return;
658 }
659
660 fibril_mutex_lock(&cdir.mutex);
661
662 cat = category_get(&cdir, ipc_get_arg1(icall));
663 if (cat == NULL) {
664 fibril_mutex_unlock(&cdir.mutex);
665 async_answer_0(&call, ENOENT);
666 async_answer_0(icall, ENOENT);
667 return;
668 }
669
670 act_size = str_size(cat->name);
671 if (act_size > size) {
672 fibril_mutex_unlock(&cdir.mutex);
673 async_answer_0(&call, EOVERFLOW);
674 async_answer_0(icall, EOVERFLOW);
675 return;
676 }
677
678 errno_t retval = async_data_read_finalize(&call, cat->name,
679 min(size, act_size));
680
681 fibril_mutex_unlock(&cdir.mutex);
682
683 async_answer_0(icall, retval);
684}
685
686static void loc_service_get_name(ipc_call_t *icall)
687{
688 ipc_call_t call;
689 size_t size;
690 size_t act_size;
691 loc_service_t *svc;
692 char *fqn;
693
694 if (!async_data_read_receive(&call, &size)) {
695 async_answer_0(&call, EREFUSED);
696 async_answer_0(icall, EREFUSED);
697 return;
698 }
699
700 fibril_mutex_lock(&services_list_mutex);
701
702 svc = loc_service_find_id(ipc_get_arg1(icall));
703 if (svc == NULL) {
704 fibril_mutex_unlock(&services_list_mutex);
705 async_answer_0(&call, ENOENT);
706 async_answer_0(icall, ENOENT);
707 return;
708 }
709
710 if (asprintf(&fqn, "%s/%s", svc->namespace->name, svc->name) < 0) {
711 fibril_mutex_unlock(&services_list_mutex);
712 async_answer_0(&call, ENOMEM);
713 async_answer_0(icall, ENOMEM);
714 return;
715 }
716
717 act_size = str_size(fqn);
718 if (act_size > size) {
719 free(fqn);
720 fibril_mutex_unlock(&services_list_mutex);
721 async_answer_0(&call, EOVERFLOW);
722 async_answer_0(icall, EOVERFLOW);
723 return;
724 }
725
726 errno_t retval = async_data_read_finalize(&call, fqn,
727 min(size, act_size));
728 free(fqn);
729
730 fibril_mutex_unlock(&services_list_mutex);
731
732 async_answer_0(icall, retval);
733}
734
735static void loc_service_get_server_name(ipc_call_t *icall)
736{
737 ipc_call_t call;
738 size_t size;
739 size_t act_size;
740 loc_service_t *svc;
741
742 if (!async_data_read_receive(&call, &size)) {
743 async_answer_0(&call, EREFUSED);
744 async_answer_0(icall, EREFUSED);
745 return;
746 }
747
748 fibril_mutex_lock(&services_list_mutex);
749
750 svc = loc_service_find_id(ipc_get_arg1(icall));
751 if (svc == NULL) {
752 fibril_mutex_unlock(&services_list_mutex);
753 async_answer_0(&call, ENOENT);
754 async_answer_0(icall, ENOENT);
755 return;
756 }
757
758 if (svc->server == NULL) {
759 fibril_mutex_unlock(&services_list_mutex);
760 async_answer_0(&call, EINVAL);
761 async_answer_0(icall, EINVAL);
762 return;
763 }
764
765 act_size = str_size(svc->server->name);
766 if (act_size > size) {
767 fibril_mutex_unlock(&services_list_mutex);
768 async_answer_0(&call, EOVERFLOW);
769 async_answer_0(icall, EOVERFLOW);
770 return;
771 }
772
773 errno_t retval = async_data_read_finalize(&call, svc->server->name,
774 min(size, act_size));
775
776 fibril_mutex_unlock(&services_list_mutex);
777
778 async_answer_0(icall, retval);
779}
780
781/** Connect client to the service.
782 *
783 * Find server supplying requested service and forward
784 * the message to it.
785 *
786 */
787static void loc_forward(ipc_call_t *call, void *arg)
788{
789 fibril_mutex_lock(&services_list_mutex);
790
791 /*
792 * Get ID from request
793 */
794 iface_t iface = ipc_get_arg1(call);
795 service_id_t id = ipc_get_arg2(call);
796 loc_service_t *svc = loc_service_find_id(id);
797
798 if ((svc == NULL) || (svc->server == NULL) || (!svc->server->sess)) {
799 fibril_mutex_unlock(&services_list_mutex);
800 async_answer_0(call, ENOENT);
801 return;
802 }
803
804 async_exch_t *exch = async_exchange_begin(svc->server->sess);
805 async_forward_1(call, exch, iface, svc->id, IPC_FF_NONE);
806 async_exchange_end(exch);
807
808 fibril_mutex_unlock(&services_list_mutex);
809}
810
811/** Find ID for service identified by name.
812 *
813 * In answer will be send EOK and service ID in arg1 or a error
814 * code from errno.h.
815 *
816 */
817static void loc_service_get_id(ipc_call_t *icall)
818{
819 char *fqsn;
820
821 /* Get fqsn */
822 errno_t rc = async_data_write_accept((void **) &fqsn, true, 0,
823 LOC_NAME_MAXLEN, 0, NULL);
824 if (rc != EOK) {
825 async_answer_0(icall, rc);
826 return;
827 }
828
829 char *ns_name;
830 char *name;
831 if (!loc_fqsn_split(fqsn, &ns_name, &name)) {
832 free(fqsn);
833 async_answer_0(icall, EINVAL);
834 return;
835 }
836
837 free(fqsn);
838
839 fibril_mutex_lock(&services_list_mutex);
840 const loc_service_t *svc;
841 int flags = ipc_get_arg1(icall);
842 bool start_requested = false;
843
844recheck:
845
846 /*
847 * Find service name in the list of known services.
848 */
849 svc = loc_service_find_name(ns_name, name);
850
851 /*
852 * Service was not found.
853 */
854 if (svc == NULL) {
855 /*
856 * TODO:
857 * Consider non-blocking service start, return some dummy id
858 * and block only after connection request (actually makes more
859 * sense as those who asks for ID might be someone else than
860 * those connecting)
861 *
862 * Note:
863 * service_list_mutex is released as we don't need to keep it
864 * while waiting for start request to finish.
865 */
866 if ((flags & IPC_FLAG_AUTOSTART_) && !start_requested) {
867 fibril_mutex_unlock(&services_list_mutex);
868 rc = loc_service_request_start(ns_name, name);
869 fibril_mutex_lock(&services_list_mutex);
870 start_requested = true;
871
872 if (rc != EOK) {
873 goto finish;
874 } else {
875 goto recheck;
876 }
877 }
878
879 if ((flags & IPC_FLAG_BLOCKING) || flags & IPC_FLAG_AUTOSTART_) {
880 fibril_condvar_wait(&services_list_cv,
881 &services_list_mutex);
882 goto recheck;
883 }
884 rc = ENOENT;
885 } else {
886 rc = EOK;
887 }
888
889finish:
890 if (rc == EOK) {
891 async_answer_1(icall, EOK, svc->id);
892 } else {
893 async_answer_0(icall, rc);
894 }
895
896 fibril_mutex_unlock(&services_list_mutex);
897 free(ns_name);
898 free(name);
899}
900
901/** Find ID for namespace identified by name.
902 *
903 * In answer will be send EOK and service ID in arg1 or a error
904 * code from errno.h.
905 *
906 */
907static void loc_namespace_get_id(ipc_call_t *icall)
908{
909 char *name;
910
911 /* Get service name */
912 errno_t rc = async_data_write_accept((void **) &name, true, 0,
913 LOC_NAME_MAXLEN, 0, NULL);
914 if (rc != EOK) {
915 async_answer_0(icall, rc);
916 return;
917 }
918
919 fibril_mutex_lock(&services_list_mutex);
920 const loc_namespace_t *namespace;
921
922recheck:
923
924 /*
925 * Find namespace name in the list of known namespaces.
926 */
927 namespace = loc_namespace_find_name(name);
928
929 /*
930 * Namespace was not found.
931 */
932 if (namespace == NULL) {
933 if (ipc_get_arg1(icall) & IPC_FLAG_BLOCKING) {
934 /* Blocking lookup */
935 fibril_condvar_wait(&services_list_cv,
936 &services_list_mutex);
937 goto recheck;
938 }
939
940 async_answer_0(icall, ENOENT);
941 free(name);
942 fibril_mutex_unlock(&services_list_mutex);
943 return;
944 }
945
946 async_answer_1(icall, EOK, namespace->id);
947
948 fibril_mutex_unlock(&services_list_mutex);
949 free(name);
950}
951
952/** Create callback connection.
953 *
954 * Create callback connection which will be used to send category change
955 * events.
956 *
957 * On success, answer will contain EOK errno_t retval.
958 * On failure, error code will be sent in retval.
959 *
960 */
961static void loc_callback_create(ipc_call_t *icall)
962{
963 cb_sess_t *cb_sess = calloc(1, sizeof(cb_sess_t));
964 if (cb_sess == NULL) {
965 async_answer_0(icall, ENOMEM);
966 return;
967 }
968
969 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
970 if (sess == NULL) {
971 free(cb_sess);
972 async_answer_0(icall, ENOMEM);
973 return;
974 }
975
976 cb_sess->sess = sess;
977 link_initialize(&cb_sess->cb_sess_list);
978
979 fibril_mutex_lock(&callback_sess_mutex);
980 list_append(&cb_sess->cb_sess_list, &callback_sess_list);
981 fibril_mutex_unlock(&callback_sess_mutex);
982
983 async_answer_0(icall, EOK);
984}
985
986void loc_category_change_event(void)
987{
988 fibril_mutex_lock(&callback_sess_mutex);
989
990 list_foreach(callback_sess_list, cb_sess_list, cb_sess_t, cb_sess) {
991 async_exch_t *exch = async_exchange_begin(cb_sess->sess);
992 async_msg_0(exch, LOC_EVENT_CAT_CHANGE);
993 async_exchange_end(exch);
994 }
995
996 fibril_mutex_unlock(&callback_sess_mutex);
997}
998
999/** Find ID for category specified by name.
1000 *
1001 * On success, answer will contain EOK errno_t retval and service ID in arg1.
1002 * On failure, error code will be sent in retval.
1003 *
1004 */
1005static void loc_category_get_id(ipc_call_t *icall)
1006{
1007 char *name;
1008 category_t *cat;
1009
1010 /* Get service name */
1011 errno_t rc = async_data_write_accept((void **) &name, true, 0,
1012 LOC_NAME_MAXLEN, 0, NULL);
1013 if (rc != EOK) {
1014 async_answer_0(icall, rc);
1015 return;
1016 }
1017
1018 fibril_mutex_lock(&cdir.mutex);
1019
1020 cat = category_find_by_name(&cdir, name);
1021 if (cat == NULL) {
1022 /* Category not found */
1023 async_answer_0(icall, ENOENT);
1024 goto cleanup;
1025 }
1026
1027 async_answer_1(icall, EOK, cat->id);
1028cleanup:
1029 fibril_mutex_unlock(&cdir.mutex);
1030 free(name);
1031}
1032
1033static void loc_id_probe(ipc_call_t *icall)
1034{
1035 fibril_mutex_lock(&services_list_mutex);
1036
1037 loc_namespace_t *namespace =
1038 loc_namespace_find_id(ipc_get_arg1(icall));
1039 if (namespace == NULL) {
1040 loc_service_t *svc =
1041 loc_service_find_id(ipc_get_arg1(icall));
1042 if (svc == NULL)
1043 async_answer_1(icall, EOK, LOC_OBJECT_NONE);
1044 else
1045 async_answer_1(icall, EOK, LOC_OBJECT_SERVICE);
1046 } else
1047 async_answer_1(icall, EOK, LOC_OBJECT_NAMESPACE);
1048
1049 fibril_mutex_unlock(&services_list_mutex);
1050}
1051
1052static void loc_get_namespace_count(ipc_call_t *icall)
1053{
1054 fibril_mutex_lock(&services_list_mutex);
1055 async_answer_1(icall, EOK, list_count(&namespaces_list));
1056 fibril_mutex_unlock(&services_list_mutex);
1057}
1058
1059static void loc_get_service_count(ipc_call_t *icall)
1060{
1061 fibril_mutex_lock(&services_list_mutex);
1062
1063 loc_namespace_t *namespace =
1064 loc_namespace_find_id(ipc_get_arg1(icall));
1065 if (namespace == NULL)
1066 async_answer_0(icall, EEXIST);
1067 else
1068 async_answer_1(icall, EOK, namespace->refcnt);
1069
1070 fibril_mutex_unlock(&services_list_mutex);
1071}
1072
1073static void loc_get_categories(ipc_call_t *icall)
1074{
1075 ipc_call_t call;
1076 size_t size;
1077 size_t act_size;
1078 errno_t rc;
1079
1080 if (!async_data_read_receive(&call, &size)) {
1081 async_answer_0(&call, EREFUSED);
1082 async_answer_0(icall, EREFUSED);
1083 return;
1084 }
1085
1086 category_id_t *id_buf = (category_id_t *) malloc(size);
1087 if (id_buf == NULL) {
1088 fibril_mutex_unlock(&cdir.mutex);
1089 async_answer_0(&call, ENOMEM);
1090 async_answer_0(icall, ENOMEM);
1091 return;
1092 }
1093
1094 fibril_mutex_lock(&cdir.mutex);
1095
1096 rc = categ_dir_get_categories(&cdir, id_buf, size, &act_size);
1097 if (rc != EOK) {
1098 fibril_mutex_unlock(&cdir.mutex);
1099 async_answer_0(&call, rc);
1100 async_answer_0(icall, rc);
1101 return;
1102 }
1103
1104 fibril_mutex_unlock(&cdir.mutex);
1105
1106 errno_t retval = async_data_read_finalize(&call, id_buf, size);
1107 free(id_buf);
1108
1109 async_answer_1(icall, retval, act_size);
1110}
1111
1112static void loc_get_namespaces(ipc_call_t *icall)
1113{
1114 ipc_call_t call;
1115 size_t size;
1116 if (!async_data_read_receive(&call, &size)) {
1117 async_answer_0(&call, EREFUSED);
1118 async_answer_0(icall, EREFUSED);
1119 return;
1120 }
1121
1122 if ((size % sizeof(loc_sdesc_t)) != 0) {
1123 async_answer_0(&call, EINVAL);
1124 async_answer_0(icall, EINVAL);
1125 return;
1126 }
1127
1128 fibril_mutex_lock(&services_list_mutex);
1129
1130 size_t count = size / sizeof(loc_sdesc_t);
1131 if (count != list_count(&namespaces_list)) {
1132 fibril_mutex_unlock(&services_list_mutex);
1133 async_answer_0(&call, EOVERFLOW);
1134 async_answer_0(icall, EOVERFLOW);
1135 return;
1136 }
1137
1138 loc_sdesc_t *desc = (loc_sdesc_t *) malloc(size);
1139 if (desc == NULL) {
1140 fibril_mutex_unlock(&services_list_mutex);
1141 async_answer_0(&call, ENOMEM);
1142 async_answer_0(icall, ENOMEM);
1143 return;
1144 }
1145
1146 size_t pos = 0;
1147 list_foreach(namespaces_list, namespaces, loc_namespace_t, namespace) {
1148 desc[pos].id = namespace->id;
1149 str_cpy(desc[pos].name, LOC_NAME_MAXLEN, namespace->name);
1150 pos++;
1151 }
1152
1153 errno_t retval = async_data_read_finalize(&call, desc, size);
1154
1155 free(desc);
1156 fibril_mutex_unlock(&services_list_mutex);
1157
1158 async_answer_0(icall, retval);
1159}
1160
1161static void loc_get_services(ipc_call_t *icall)
1162{
1163 /*
1164 * FIXME: Use faster algorithm which can make better use
1165 * of namespaces
1166 */
1167
1168 ipc_call_t call;
1169 size_t size;
1170 if (!async_data_read_receive(&call, &size)) {
1171 async_answer_0(&call, EREFUSED);
1172 async_answer_0(icall, EREFUSED);
1173 return;
1174 }
1175
1176 if ((size % sizeof(loc_sdesc_t)) != 0) {
1177 async_answer_0(&call, EINVAL);
1178 async_answer_0(icall, EINVAL);
1179 return;
1180 }
1181
1182 fibril_mutex_lock(&services_list_mutex);
1183
1184 loc_namespace_t *namespace =
1185 loc_namespace_find_id(ipc_get_arg1(icall));
1186 if (namespace == NULL) {
1187 fibril_mutex_unlock(&services_list_mutex);
1188 async_answer_0(&call, ENOENT);
1189 async_answer_0(icall, ENOENT);
1190 return;
1191 }
1192
1193 size_t count = size / sizeof(loc_sdesc_t);
1194 if (count != namespace->refcnt) {
1195 fibril_mutex_unlock(&services_list_mutex);
1196 async_answer_0(&call, EOVERFLOW);
1197 async_answer_0(icall, EOVERFLOW);
1198 return;
1199 }
1200
1201 loc_sdesc_t *desc = (loc_sdesc_t *) malloc(size);
1202 if (desc == NULL) {
1203 fibril_mutex_unlock(&services_list_mutex);
1204 async_answer_0(&call, ENOMEM);
1205 async_answer_0(icall, EREFUSED);
1206 return;
1207 }
1208
1209 size_t pos = 0;
1210 list_foreach(services_list, services, loc_service_t, service) {
1211 if (service->namespace == namespace) {
1212 desc[pos].id = service->id;
1213 str_cpy(desc[pos].name, LOC_NAME_MAXLEN, service->name);
1214 pos++;
1215 }
1216 }
1217
1218 errno_t retval = async_data_read_finalize(&call, desc, size);
1219
1220 free(desc);
1221 fibril_mutex_unlock(&services_list_mutex);
1222
1223 async_answer_0(icall, retval);
1224}
1225
1226static void loc_category_get_svcs(ipc_call_t *icall)
1227{
1228 ipc_call_t call;
1229 size_t size;
1230 size_t act_size;
1231 errno_t rc;
1232
1233 if (!async_data_read_receive(&call, &size)) {
1234 async_answer_0(&call, EREFUSED);
1235 async_answer_0(icall, EREFUSED);
1236 return;
1237 }
1238
1239 fibril_mutex_lock(&cdir.mutex);
1240
1241 category_t *cat = category_get(&cdir, ipc_get_arg1(icall));
1242 if (cat == NULL) {
1243 fibril_mutex_unlock(&cdir.mutex);
1244 async_answer_0(&call, ENOENT);
1245 async_answer_0(icall, ENOENT);
1246 return;
1247 }
1248
1249 category_id_t *id_buf = (category_id_t *) malloc(size);
1250 if (id_buf == NULL) {
1251 fibril_mutex_unlock(&cdir.mutex);
1252 async_answer_0(&call, ENOMEM);
1253 async_answer_0(icall, ENOMEM);
1254 return;
1255 }
1256
1257 fibril_mutex_lock(&cat->mutex);
1258
1259 rc = category_get_services(cat, id_buf, size, &act_size);
1260 if (rc != EOK) {
1261 fibril_mutex_unlock(&cat->mutex);
1262 fibril_mutex_unlock(&cdir.mutex);
1263 async_answer_0(&call, rc);
1264 async_answer_0(icall, rc);
1265 return;
1266 }
1267
1268 fibril_mutex_unlock(&cat->mutex);
1269 fibril_mutex_unlock(&cdir.mutex);
1270
1271 errno_t retval = async_data_read_finalize(&call, id_buf, size);
1272 free(id_buf);
1273
1274 async_answer_1(icall, retval, act_size);
1275}
1276
1277static void loc_null_create(ipc_call_t *icall)
1278{
1279 fibril_mutex_lock(&null_services_mutex);
1280
1281 unsigned int i;
1282 bool fnd = false;
1283
1284 for (i = 0; i < NULL_SERVICES; i++) {
1285 if (null_services[i] == NULL) {
1286 fnd = true;
1287 break;
1288 }
1289 }
1290
1291 if (!fnd) {
1292 fibril_mutex_unlock(&null_services_mutex);
1293 async_answer_0(icall, ENOMEM);
1294 return;
1295 }
1296
1297 char null[LOC_NAME_MAXLEN];
1298 snprintf(null, LOC_NAME_MAXLEN, "%u", i);
1299
1300 char *dev_name = str_dup(null);
1301 if (dev_name == NULL) {
1302 fibril_mutex_unlock(&null_services_mutex);
1303 async_answer_0(icall, ENOMEM);
1304 return;
1305 }
1306
1307 loc_service_t *service =
1308 (loc_service_t *) malloc(sizeof(loc_service_t));
1309 if (service == NULL) {
1310 fibril_mutex_unlock(&null_services_mutex);
1311 async_answer_0(icall, ENOMEM);
1312 return;
1313 }
1314
1315 fibril_mutex_lock(&services_list_mutex);
1316
1317 loc_namespace_t *namespace = loc_namespace_create("null");
1318 if (namespace == NULL) {
1319 fibril_mutex_lock(&services_list_mutex);
1320 fibril_mutex_unlock(&null_services_mutex);
1321 async_answer_0(icall, ENOMEM);
1322 return;
1323 }
1324
1325 link_initialize(&service->services);
1326 link_initialize(&service->server_services);
1327 list_initialize(&service->cat_memb);
1328
1329 /* Get unique service ID */
1330 service->id = loc_create_id();
1331 service->server = NULL;
1332
1333 loc_namespace_addref(namespace, service);
1334 service->name = dev_name;
1335
1336 /*
1337 * Insert service into list of all services and into null services array.
1338 * Insert service into a dummy list of null server's services so that it
1339 * can be safely removed later.
1340 */
1341 list_append(&service->services, &services_list);
1342 list_append(&service->server_services, &dummy_null_services);
1343 null_services[i] = service;
1344
1345 fibril_mutex_unlock(&services_list_mutex);
1346 fibril_mutex_unlock(&null_services_mutex);
1347
1348 async_answer_1(icall, EOK, (sysarg_t) i);
1349}
1350
1351static void loc_null_destroy(ipc_call_t *icall)
1352{
1353 sysarg_t i = ipc_get_arg1(icall);
1354 if (i >= NULL_SERVICES) {
1355 async_answer_0(icall, ELIMIT);
1356 return;
1357 }
1358
1359 fibril_mutex_lock(&null_services_mutex);
1360
1361 if (null_services[i] == NULL) {
1362 fibril_mutex_unlock(&null_services_mutex);
1363 async_answer_0(icall, ENOENT);
1364 return;
1365 }
1366
1367 fibril_mutex_lock(&services_list_mutex);
1368 fibril_mutex_lock(&cdir.mutex);
1369 loc_service_unregister_core(null_services[i]);
1370 fibril_mutex_unlock(&cdir.mutex);
1371 fibril_mutex_unlock(&services_list_mutex);
1372
1373 null_services[i] = NULL;
1374
1375 fibril_mutex_unlock(&null_services_mutex);
1376 async_answer_0(icall, EOK);
1377}
1378
1379static void loc_service_add_to_cat(ipc_call_t *icall)
1380{
1381 category_t *cat;
1382 loc_service_t *svc;
1383 catid_t cat_id;
1384 service_id_t svc_id;
1385 errno_t retval;
1386
1387 svc_id = ipc_get_arg1(icall);
1388 cat_id = ipc_get_arg2(icall);
1389
1390 fibril_mutex_lock(&services_list_mutex);
1391 fibril_mutex_lock(&cdir.mutex);
1392
1393 cat = category_get(&cdir, cat_id);
1394 svc = loc_service_find_id(svc_id);
1395
1396 if (cat == NULL || svc == NULL) {
1397 fibril_mutex_unlock(&cdir.mutex);
1398 fibril_mutex_unlock(&services_list_mutex);
1399 async_answer_0(icall, ENOENT);
1400 return;
1401 }
1402
1403 fibril_mutex_lock(&cat->mutex);
1404 retval = category_add_service(cat, svc);
1405
1406 fibril_mutex_unlock(&cat->mutex);
1407 fibril_mutex_unlock(&cdir.mutex);
1408 fibril_mutex_unlock(&services_list_mutex);
1409
1410 /*
1411 * First send out all notifications and only then answer the request.
1412 * Otherwise the current fibril might block and transitively wait for
1413 * the completion of requests that are routed to it via an IPC loop.
1414 */
1415 loc_category_change_event();
1416 async_answer_0(icall, retval);
1417}
1418
1419/** Initialize location service.
1420 *
1421 *
1422 */
1423static bool loc_init(void)
1424{
1425 unsigned int i;
1426 category_t *cat;
1427
1428 for (i = 0; i < NULL_SERVICES; i++)
1429 null_services[i] = NULL;
1430
1431 categ_dir_init(&cdir);
1432
1433 cat = category_new("disk");
1434 categ_dir_add_cat(&cdir, cat);
1435
1436 cat = category_new("partition");
1437 categ_dir_add_cat(&cdir, cat);
1438
1439 cat = category_new("iplink");
1440 categ_dir_add_cat(&cdir, cat);
1441
1442 cat = category_new("keyboard");
1443 categ_dir_add_cat(&cdir, cat);
1444
1445 cat = category_new("mouse");
1446 categ_dir_add_cat(&cdir, cat);
1447
1448 cat = category_new("led");
1449 categ_dir_add_cat(&cdir, cat);
1450
1451 cat = category_new("serial");
1452 categ_dir_add_cat(&cdir, cat);
1453
1454 cat = category_new("console");
1455 categ_dir_add_cat(&cdir, cat);
1456
1457 cat = category_new("clock");
1458 categ_dir_add_cat(&cdir, cat);
1459
1460 cat = category_new("test3");
1461 categ_dir_add_cat(&cdir, cat);
1462
1463 cat = category_new("usbdiag");
1464 categ_dir_add_cat(&cdir, cat);
1465
1466 cat = category_new("usbhc");
1467 categ_dir_add_cat(&cdir, cat);
1468
1469 cat = category_new("virt-null");
1470 categ_dir_add_cat(&cdir, cat);
1471
1472 cat = category_new("virtual");
1473 categ_dir_add_cat(&cdir, cat);
1474
1475 cat = category_new("nic");
1476 categ_dir_add_cat(&cdir, cat);
1477
1478 cat = category_new("ieee80211");
1479 categ_dir_add_cat(&cdir, cat);
1480
1481 cat = category_new("irc");
1482 categ_dir_add_cat(&cdir, cat);
1483
1484 cat = category_new("visualizer");
1485 categ_dir_add_cat(&cdir, cat);
1486
1487 cat = category_new("renderer");
1488 categ_dir_add_cat(&cdir, cat);
1489
1490 cat = category_new("audio-pcm");
1491 categ_dir_add_cat(&cdir, cat);
1492
1493 cat = category_new("printer-port");
1494 categ_dir_add_cat(&cdir, cat);
1495
1496 cat = category_new("pci");
1497 categ_dir_add_cat(&cdir, cat);
1498
1499 return true;
1500}
1501
1502/** Handle connection on supplier port.
1503 *
1504 */
1505static void loc_connection_supplier(ipc_call_t *icall, void *arg)
1506{
1507 /* Accept connection */
1508 async_accept_0(icall);
1509
1510 /*
1511 * Each connection begins by a LOC_SERVER_REGISTER, which precludes us
1512 * from using parallel exchanges.
1513 */
1514 static_assert((INTERFACE_LOC_SUPPLIER & IFACE_EXCHANGE_MASK) ==
1515 IFACE_EXCHANGE_SERIALIZE, "");
1516
1517 loc_server_t *server = loc_server_register();
1518 if (server == NULL)
1519 return;
1520
1521 while (true) {
1522 ipc_call_t call;
1523 async_get_call(&call);
1524
1525 if (!ipc_get_imethod(&call)) {
1526 async_answer_0(&call, EOK);
1527 break;
1528 }
1529
1530 switch (ipc_get_imethod(&call)) {
1531 case LOC_SERVER_UNREGISTER:
1532 if (server == NULL)
1533 async_answer_0(&call, ENOENT);
1534 else
1535 async_answer_0(&call, EOK);
1536 break;
1537 case LOC_SERVICE_ADD_TO_CAT:
1538 /* Add service to category */
1539 loc_service_add_to_cat(&call);
1540 break;
1541 case LOC_SERVICE_REGISTER:
1542 /* Register one service */
1543 loc_service_register(&call, server);
1544 break;
1545 case LOC_SERVICE_UNREGISTER:
1546 /* Remove one service */
1547 loc_service_unregister(&call, server);
1548 break;
1549 case LOC_SERVICE_GET_ID:
1550 loc_service_get_id(&call);
1551 break;
1552 case LOC_NAMESPACE_GET_ID:
1553 loc_namespace_get_id(&call);
1554 break;
1555 default:
1556 async_answer_0(&call, ENOENT);
1557 }
1558 }
1559
1560 if (server != NULL) {
1561 /*
1562 * Unregister the server and all its services.
1563 */
1564 loc_server_unregister(server);
1565 server = NULL;
1566 }
1567}
1568
1569/** Handle connection on consumer port.
1570 *
1571 */
1572static void loc_connection_consumer(ipc_call_t *icall, void *arg)
1573{
1574 /* Accept connection */
1575 async_accept_0(icall);
1576
1577 while (true) {
1578 ipc_call_t call;
1579 async_get_call(&call);
1580
1581 if (!ipc_get_imethod(&call)) {
1582 async_answer_0(&call, EOK);
1583 break;
1584 }
1585
1586 switch (ipc_get_imethod(&call)) {
1587 case LOC_SERVICE_GET_ID:
1588 loc_service_get_id(&call);
1589 break;
1590 case LOC_SERVICE_GET_NAME:
1591 loc_service_get_name(&call);
1592 break;
1593 case LOC_SERVICE_GET_SERVER_NAME:
1594 loc_service_get_server_name(&call);
1595 break;
1596 case LOC_NAMESPACE_GET_ID:
1597 loc_namespace_get_id(&call);
1598 break;
1599 case LOC_CALLBACK_CREATE:
1600 loc_callback_create(&call);
1601 break;
1602 case LOC_CATEGORY_GET_ID:
1603 loc_category_get_id(&call);
1604 break;
1605 case LOC_CATEGORY_GET_NAME:
1606 loc_category_get_name(&call);
1607 break;
1608 case LOC_CATEGORY_GET_SVCS:
1609 loc_category_get_svcs(&call);
1610 break;
1611 case LOC_ID_PROBE:
1612 loc_id_probe(&call);
1613 break;
1614 case LOC_NULL_CREATE:
1615 loc_null_create(&call);
1616 break;
1617 case LOC_NULL_DESTROY:
1618 loc_null_destroy(&call);
1619 break;
1620 case LOC_GET_NAMESPACE_COUNT:
1621 loc_get_namespace_count(&call);
1622 break;
1623 case LOC_GET_SERVICE_COUNT:
1624 loc_get_service_count(&call);
1625 break;
1626 case LOC_GET_CATEGORIES:
1627 loc_get_categories(&call);
1628 break;
1629 case LOC_GET_NAMESPACES:
1630 loc_get_namespaces(&call);
1631 break;
1632 case LOC_GET_SERVICES:
1633 loc_get_services(&call);
1634 break;
1635 default:
1636 async_answer_0(&call, ENOENT);
1637 }
1638 }
1639}
1640
1641/**
1642 *
1643 */
1644int main(int argc, char *argv[])
1645{
1646 printf("%s: HelenOS Location Service\n", NAME);
1647
1648 if (!loc_init()) {
1649 printf("%s: Error while initializing service\n", NAME);
1650 return -1;
1651 }
1652
1653 /* Register location service at naming service */
1654 errno_t rc = service_register(SERVICE_LOC, INTERFACE_LOC_SUPPLIER,
1655 loc_connection_supplier, NULL);
1656 if (rc != EOK) {
1657 printf("%s: Error while registering supplier service: %s\n", NAME, str_error(rc));
1658 return rc;
1659 }
1660
1661 rc = service_register(SERVICE_LOC, INTERFACE_LOC_CONSUMER,
1662 loc_connection_consumer, NULL);
1663 if (rc != EOK) {
1664 printf("%s: Error while registering consumer service: %s\n", NAME, str_error(rc));
1665 return rc;
1666 }
1667
1668 rc = service_register_broker(SERVICE_LOC, loc_forward, NULL);
1669 if (rc != EOK) {
1670 printf("%s: Error while registering broker service: %s\n", NAME, str_error(rc));
1671 return rc;
1672 }
1673
1674 /* Let sysman know we are broker */
1675 rc = sysman_broker_register();
1676 if (rc != EOK) {
1677 printf("%s: Error registering at sysman (%i)\n", NAME, rc);
1678 return rc;
1679 }
1680
1681 printf("%s: Accepting connections\n", NAME);
1682 task_retval(0);
1683 async_manager();
1684
1685 /* Never reached */
1686 return 0;
1687}
1688
1689/**
1690 * @}
1691 */
Note: See TracBrowser for help on using the repository browser.