source: mainline/uspace/srv/locsrv/locsrv.c@ 918ac9b

Last change on this file since 918ac9b was 63a3276, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

sysman: Instrumented locsrv for autostart

  • also refactored unit name derivation in other brokers
  • exposee creation is not used in unit's lifecycle (failed assertion)

Conflicts:

uspace/lib/c/generic/loc.c
uspace/srv/devman/driver.c
uspace/srv/devman/drv_conn.c
uspace/srv/hid/compositor/compositor.c
uspace/srv/locsrv/locsrv.c
uspace/srv/vfs/vfs.h
uspace/srv/vfs/vfs_ops.c
uspace/srv/vfs/vfs_register.c

  • 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(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(iid, 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->in_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_callid_t iid, ipc_call_t *icall,
622 loc_server_t *server)
623{
624 loc_service_t *svc;
625
626 fibril_mutex_lock(&services_list_mutex);
627 svc = loc_service_find_id(ipc_get_arg1(icall));
628 if (svc == NULL) {
629 fibril_mutex_unlock(&services_list_mutex);
630 async_answer_0(icall, ENOENT);
631 return;
632 }
633
634 fibril_mutex_lock(&cdir.mutex);
635 loc_service_unregister_core(svc);
636 fibril_mutex_unlock(&cdir.mutex);
637 fibril_mutex_unlock(&services_list_mutex);
638
639 /*
640 * First send out all notifications and only then answer the request.
641 * Otherwise the current fibril might block and transitively wait for
642 * the completion of requests that are routed to it via an IPC loop.
643 */
644 loc_category_change_event();
645 async_answer_0(icall, EOK);
646}
647
648static void loc_category_get_name(ipc_call_t *icall)
649{
650 ipc_call_t call;
651 size_t size;
652 size_t act_size;
653 category_t *cat;
654
655 if (!async_data_read_receive(&call, &size)) {
656 async_answer_0(&call, EREFUSED);
657 async_answer_0(icall, EREFUSED);
658 return;
659 }
660
661 fibril_mutex_lock(&cdir.mutex);
662
663 cat = category_get(&cdir, ipc_get_arg1(icall));
664 if (cat == NULL) {
665 fibril_mutex_unlock(&cdir.mutex);
666 async_answer_0(&call, ENOENT);
667 async_answer_0(icall, ENOENT);
668 return;
669 }
670
671 act_size = str_size(cat->name);
672 if (act_size > size) {
673 fibril_mutex_unlock(&cdir.mutex);
674 async_answer_0(&call, EOVERFLOW);
675 async_answer_0(icall, EOVERFLOW);
676 return;
677 }
678
679 errno_t retval = async_data_read_finalize(&call, cat->name,
680 min(size, act_size));
681
682 fibril_mutex_unlock(&cdir.mutex);
683
684 async_answer_0(icall, retval);
685}
686
687static void loc_service_get_name(ipc_call_t *icall)
688{
689 ipc_call_t call;
690 size_t size;
691 size_t act_size;
692 loc_service_t *svc;
693 char *fqn;
694
695 if (!async_data_read_receive(&call, &size)) {
696 async_answer_0(&call, EREFUSED);
697 async_answer_0(icall, EREFUSED);
698 return;
699 }
700
701 fibril_mutex_lock(&services_list_mutex);
702
703 svc = loc_service_find_id(ipc_get_arg1(icall));
704 if (svc == NULL) {
705 fibril_mutex_unlock(&services_list_mutex);
706 async_answer_0(&call, ENOENT);
707 async_answer_0(icall, ENOENT);
708 return;
709 }
710
711 if (asprintf(&fqn, "%s/%s", svc->namespace->name, svc->name) < 0) {
712 fibril_mutex_unlock(&services_list_mutex);
713 async_answer_0(&call, ENOMEM);
714 async_answer_0(icall, ENOMEM);
715 return;
716 }
717
718 act_size = str_size(fqn);
719 if (act_size > size) {
720 free(fqn);
721 fibril_mutex_unlock(&services_list_mutex);
722 async_answer_0(&call, EOVERFLOW);
723 async_answer_0(icall, EOVERFLOW);
724 return;
725 }
726
727 errno_t retval = async_data_read_finalize(&call, fqn,
728 min(size, act_size));
729 free(fqn);
730
731 fibril_mutex_unlock(&services_list_mutex);
732
733 async_answer_0(icall, retval);
734}
735
736static void loc_service_get_server_name(ipc_call_t *icall)
737{
738 ipc_call_t call;
739 size_t size;
740 size_t act_size;
741 loc_service_t *svc;
742
743 if (!async_data_read_receive(&call, &size)) {
744 async_answer_0(&call, EREFUSED);
745 async_answer_0(icall, EREFUSED);
746 return;
747 }
748
749 fibril_mutex_lock(&services_list_mutex);
750
751 svc = loc_service_find_id(ipc_get_arg1(icall));
752 if (svc == NULL) {
753 fibril_mutex_unlock(&services_list_mutex);
754 async_answer_0(&call, ENOENT);
755 async_answer_0(icall, ENOENT);
756 return;
757 }
758
759 if (svc->server == NULL) {
760 fibril_mutex_unlock(&services_list_mutex);
761 async_answer_0(&call, EINVAL);
762 async_answer_0(icall, EINVAL);
763 return;
764 }
765
766 act_size = str_size(svc->server->name);
767 if (act_size > size) {
768 fibril_mutex_unlock(&services_list_mutex);
769 async_answer_0(&call, EOVERFLOW);
770 async_answer_0(icall, EOVERFLOW);
771 return;
772 }
773
774 errno_t retval = async_data_read_finalize(&call, svc->server->name,
775 min(size, act_size));
776
777 fibril_mutex_unlock(&services_list_mutex);
778
779 async_answer_0(icall, retval);
780}
781
782/** Connect client to the service.
783 *
784 * Find server supplying requested service and forward
785 * the message to it.
786 *
787 */
788static void loc_forward(ipc_call_t *call, void *arg)
789{
790 fibril_mutex_lock(&services_list_mutex);
791
792 /*
793 * Get ID from request
794 */
795 iface_t iface = ipc_get_arg1(call);
796 service_id_t id = ipc_get_arg2(call);
797 loc_service_t *svc = loc_service_find_id(id);
798
799 if ((svc == NULL) || (svc->server == NULL) || (!svc->server->sess)) {
800 fibril_mutex_unlock(&services_list_mutex);
801 async_answer_0(call, ENOENT);
802 return;
803 }
804
805 async_exch_t *exch = async_exchange_begin(svc->server->sess);
806 async_forward_1(call, exch, iface, svc->id, IPC_FF_NONE);
807 async_exchange_end(exch);
808
809 fibril_mutex_unlock(&services_list_mutex);
810}
811
812/** Find ID for service identified by name.
813 *
814 * In answer will be send EOK and service ID in arg1 or a error
815 * code from errno.h.
816 *
817 */
818static void loc_service_get_id(ipc_call_t *icall)
819{
820 char *fqsn;
821
822 /* Get fqsn */
823 errno_t rc = async_data_write_accept((void **) &fqsn, true, 0,
824 LOC_NAME_MAXLEN, 0, NULL);
825 if (rc != EOK) {
826 async_answer_0(icall, rc);
827 return;
828 }
829
830 char *ns_name;
831 char *name;
832 if (!loc_fqsn_split(fqsn, &ns_name, &name)) {
833 free(fqsn);
834 async_answer_0(icall, EINVAL);
835 return;
836 }
837
838 free(fqsn);
839
840 fibril_mutex_lock(&services_list_mutex);
841 const loc_service_t *svc;
842 int flags = ipc_get_arg1(*icall);
843 bool start_requested = false;
844
845recheck:
846
847 /*
848 * Find service name in the list of known services.
849 */
850 svc = loc_service_find_name(ns_name, name);
851
852 /*
853 * Service was not found.
854 */
855 if (svc == NULL) {
856 /* TODO:
857 * consider non-blocking service start, return
858 * some dummy id and block only after connection
859 * request (actually makes more sense as those who asks
860 * for ID might be someone else than those connecting)
861 * Note:
862 * service_list_mutex is released as we don't need to keep it
863 * while waiting for start request to finish.
864 */
865 if ((flags & IPC_FLAG_AUTOSTART) && !start_requested) {
866 fibril_mutex_unlock(&services_list_mutex);
867 rc = loc_service_request_start(ns_name, name);
868 fibril_mutex_lock(&services_list_mutex);
869 start_requested = true;
870
871 if (rc != EOK) {
872 goto finish;
873 } else {
874 goto recheck;
875 }
876 }
877
878 if ((flags & IPC_FLAG_BLOCKING) || flags & IPC_FLAG_AUTOSTART) {
879 fibril_condvar_wait(&services_list_cv,
880 &services_list_mutex);
881 goto recheck;
882 }
883 rc = ENOENT;
884 } else {
885 rc = EOK;
886 }
887
888finish:
889 if (rc == EOK) {
890 async_answer_1(iid, EOK, svc->id);
891 } else {
892 async_answer_0(iid, rc);
893 }
894
895 fibril_mutex_unlock(&services_list_mutex);
896 free(ns_name);
897 free(name);
898}
899
900/** Find ID for namespace identified by name.
901 *
902 * In answer will be send EOK and service ID in arg1 or a error
903 * code from errno.h.
904 *
905 */
906static void loc_namespace_get_id(ipc_call_t *icall)
907{
908 char *name;
909
910 /* Get service name */
911 errno_t rc = async_data_write_accept((void **) &name, true, 0,
912 LOC_NAME_MAXLEN, 0, NULL);
913 if (rc != EOK) {
914 async_answer_0(icall, rc);
915 return;
916 }
917
918 fibril_mutex_lock(&services_list_mutex);
919 const loc_namespace_t *namespace;
920
921recheck:
922
923 /*
924 * Find namespace name in the list of known namespaces.
925 */
926 namespace = loc_namespace_find_name(name);
927
928 /*
929 * Namespace was not found.
930 */
931 if (namespace == NULL) {
932 if (ipc_get_arg1(icall) & IPC_FLAG_BLOCKING) {
933 /* Blocking lookup */
934 fibril_condvar_wait(&services_list_cv,
935 &services_list_mutex);
936 goto recheck;
937 }
938
939 async_answer_0(icall, ENOENT);
940 free(name);
941 fibril_mutex_unlock(&services_list_mutex);
942 return;
943 }
944
945 async_answer_1(icall, EOK, namespace->id);
946
947 fibril_mutex_unlock(&services_list_mutex);
948 free(name);
949}
950
951/** Create callback connection.
952 *
953 * Create callback connection which will be used to send category change
954 * events.
955 *
956 * On success, answer will contain EOK errno_t retval.
957 * On failure, error code will be sent in retval.
958 *
959 */
960static void loc_callback_create(ipc_call_t *icall)
961{
962 cb_sess_t *cb_sess = calloc(1, sizeof(cb_sess_t));
963 if (cb_sess == NULL) {
964 async_answer_0(icall, ENOMEM);
965 return;
966 }
967
968 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
969 if (sess == NULL) {
970 free(cb_sess);
971 async_answer_0(icall, ENOMEM);
972 return;
973 }
974
975 cb_sess->sess = sess;
976 link_initialize(&cb_sess->cb_sess_list);
977
978 fibril_mutex_lock(&callback_sess_mutex);
979 list_append(&cb_sess->cb_sess_list, &callback_sess_list);
980 fibril_mutex_unlock(&callback_sess_mutex);
981
982 async_answer_0(icall, EOK);
983}
984
985void loc_category_change_event(void)
986{
987 fibril_mutex_lock(&callback_sess_mutex);
988
989 list_foreach(callback_sess_list, cb_sess_list, cb_sess_t, cb_sess) {
990 async_exch_t *exch = async_exchange_begin(cb_sess->sess);
991 async_msg_0(exch, LOC_EVENT_CAT_CHANGE);
992 async_exchange_end(exch);
993 }
994
995 fibril_mutex_unlock(&callback_sess_mutex);
996}
997
998/** Find ID for category specified by name.
999 *
1000 * On success, answer will contain EOK errno_t retval and service ID in arg1.
1001 * On failure, error code will be sent in retval.
1002 *
1003 */
1004static void loc_category_get_id(ipc_call_t *icall)
1005{
1006 char *name;
1007 category_t *cat;
1008
1009 /* Get service name */
1010 errno_t rc = async_data_write_accept((void **) &name, true, 0,
1011 LOC_NAME_MAXLEN, 0, NULL);
1012 if (rc != EOK) {
1013 async_answer_0(icall, rc);
1014 return;
1015 }
1016
1017 fibril_mutex_lock(&cdir.mutex);
1018
1019 cat = category_find_by_name(&cdir, name);
1020 if (cat == NULL) {
1021 /* Category not found */
1022 async_answer_0(icall, ENOENT);
1023 goto cleanup;
1024 }
1025
1026 async_answer_1(icall, EOK, cat->id);
1027cleanup:
1028 fibril_mutex_unlock(&cdir.mutex);
1029 free(name);
1030}
1031
1032static void loc_id_probe(ipc_call_t *icall)
1033{
1034 fibril_mutex_lock(&services_list_mutex);
1035
1036 loc_namespace_t *namespace =
1037 loc_namespace_find_id(ipc_get_arg1(icall));
1038 if (namespace == NULL) {
1039 loc_service_t *svc =
1040 loc_service_find_id(ipc_get_arg1(icall));
1041 if (svc == NULL)
1042 async_answer_1(icall, EOK, LOC_OBJECT_NONE);
1043 else
1044 async_answer_1(icall, EOK, LOC_OBJECT_SERVICE);
1045 } else
1046 async_answer_1(icall, EOK, LOC_OBJECT_NAMESPACE);
1047
1048 fibril_mutex_unlock(&services_list_mutex);
1049}
1050
1051static void loc_get_namespace_count(ipc_call_t *icall)
1052{
1053 fibril_mutex_lock(&services_list_mutex);
1054 async_answer_1(icall, EOK, list_count(&namespaces_list));
1055 fibril_mutex_unlock(&services_list_mutex);
1056}
1057
1058static void loc_get_service_count(ipc_call_t *icall)
1059{
1060 fibril_mutex_lock(&services_list_mutex);
1061
1062 loc_namespace_t *namespace =
1063 loc_namespace_find_id(ipc_get_arg1(icall));
1064 if (namespace == NULL)
1065 async_answer_0(icall, EEXIST);
1066 else
1067 async_answer_1(icall, EOK, namespace->refcnt);
1068
1069 fibril_mutex_unlock(&services_list_mutex);
1070}
1071
1072static void loc_get_categories(ipc_call_t *icall)
1073{
1074 ipc_call_t call;
1075 size_t size;
1076 size_t act_size;
1077 errno_t rc;
1078
1079 if (!async_data_read_receive(&call, &size)) {
1080 async_answer_0(&call, EREFUSED);
1081 async_answer_0(icall, EREFUSED);
1082 return;
1083 }
1084
1085 category_id_t *id_buf = (category_id_t *) malloc(size);
1086 if (id_buf == NULL) {
1087 fibril_mutex_unlock(&cdir.mutex);
1088 async_answer_0(&call, ENOMEM);
1089 async_answer_0(icall, ENOMEM);
1090 return;
1091 }
1092
1093 fibril_mutex_lock(&cdir.mutex);
1094
1095 rc = categ_dir_get_categories(&cdir, id_buf, size, &act_size);
1096 if (rc != EOK) {
1097 fibril_mutex_unlock(&cdir.mutex);
1098 async_answer_0(&call, rc);
1099 async_answer_0(icall, rc);
1100 return;
1101 }
1102
1103 fibril_mutex_unlock(&cdir.mutex);
1104
1105 errno_t retval = async_data_read_finalize(&call, id_buf, size);
1106 free(id_buf);
1107
1108 async_answer_1(icall, retval, act_size);
1109}
1110
1111static void loc_get_namespaces(ipc_call_t *icall)
1112{
1113 ipc_call_t call;
1114 size_t size;
1115 if (!async_data_read_receive(&call, &size)) {
1116 async_answer_0(&call, EREFUSED);
1117 async_answer_0(icall, EREFUSED);
1118 return;
1119 }
1120
1121 if ((size % sizeof(loc_sdesc_t)) != 0) {
1122 async_answer_0(&call, EINVAL);
1123 async_answer_0(icall, EINVAL);
1124 return;
1125 }
1126
1127 fibril_mutex_lock(&services_list_mutex);
1128
1129 size_t count = size / sizeof(loc_sdesc_t);
1130 if (count != list_count(&namespaces_list)) {
1131 fibril_mutex_unlock(&services_list_mutex);
1132 async_answer_0(&call, EOVERFLOW);
1133 async_answer_0(icall, EOVERFLOW);
1134 return;
1135 }
1136
1137 loc_sdesc_t *desc = (loc_sdesc_t *) malloc(size);
1138 if (desc == NULL) {
1139 fibril_mutex_unlock(&services_list_mutex);
1140 async_answer_0(&call, ENOMEM);
1141 async_answer_0(icall, ENOMEM);
1142 return;
1143 }
1144
1145 size_t pos = 0;
1146 list_foreach(namespaces_list, namespaces, loc_namespace_t, namespace) {
1147 desc[pos].id = namespace->id;
1148 str_cpy(desc[pos].name, LOC_NAME_MAXLEN, namespace->name);
1149 pos++;
1150 }
1151
1152 errno_t retval = async_data_read_finalize(&call, desc, size);
1153
1154 free(desc);
1155 fibril_mutex_unlock(&services_list_mutex);
1156
1157 async_answer_0(icall, retval);
1158}
1159
1160static void loc_get_services(ipc_call_t *icall)
1161{
1162 /*
1163 * FIXME: Use faster algorithm which can make better use
1164 * of namespaces
1165 */
1166
1167 ipc_call_t call;
1168 size_t size;
1169 if (!async_data_read_receive(&call, &size)) {
1170 async_answer_0(&call, EREFUSED);
1171 async_answer_0(icall, EREFUSED);
1172 return;
1173 }
1174
1175 if ((size % sizeof(loc_sdesc_t)) != 0) {
1176 async_answer_0(&call, EINVAL);
1177 async_answer_0(icall, EINVAL);
1178 return;
1179 }
1180
1181 fibril_mutex_lock(&services_list_mutex);
1182
1183 loc_namespace_t *namespace =
1184 loc_namespace_find_id(ipc_get_arg1(icall));
1185 if (namespace == NULL) {
1186 fibril_mutex_unlock(&services_list_mutex);
1187 async_answer_0(&call, ENOENT);
1188 async_answer_0(icall, ENOENT);
1189 return;
1190 }
1191
1192 size_t count = size / sizeof(loc_sdesc_t);
1193 if (count != namespace->refcnt) {
1194 fibril_mutex_unlock(&services_list_mutex);
1195 async_answer_0(&call, EOVERFLOW);
1196 async_answer_0(icall, EOVERFLOW);
1197 return;
1198 }
1199
1200 loc_sdesc_t *desc = (loc_sdesc_t *) malloc(size);
1201 if (desc == NULL) {
1202 fibril_mutex_unlock(&services_list_mutex);
1203 async_answer_0(&call, ENOMEM);
1204 async_answer_0(icall, EREFUSED);
1205 return;
1206 }
1207
1208 size_t pos = 0;
1209 list_foreach(services_list, services, loc_service_t, service) {
1210 if (service->namespace == namespace) {
1211 desc[pos].id = service->id;
1212 str_cpy(desc[pos].name, LOC_NAME_MAXLEN, service->name);
1213 pos++;
1214 }
1215 }
1216
1217 errno_t retval = async_data_read_finalize(&call, desc, size);
1218
1219 free(desc);
1220 fibril_mutex_unlock(&services_list_mutex);
1221
1222 async_answer_0(icall, retval);
1223}
1224
1225static void loc_category_get_svcs(ipc_call_t *icall)
1226{
1227 ipc_call_t call;
1228 size_t size;
1229 size_t act_size;
1230 errno_t rc;
1231
1232 if (!async_data_read_receive(&call, &size)) {
1233 async_answer_0(&call, EREFUSED);
1234 async_answer_0(icall, EREFUSED);
1235 return;
1236 }
1237
1238 fibril_mutex_lock(&cdir.mutex);
1239
1240 category_t *cat = category_get(&cdir, ipc_get_arg1(icall));
1241 if (cat == NULL) {
1242 fibril_mutex_unlock(&cdir.mutex);
1243 async_answer_0(&call, ENOENT);
1244 async_answer_0(icall, ENOENT);
1245 return;
1246 }
1247
1248 category_id_t *id_buf = (category_id_t *) malloc(size);
1249 if (id_buf == NULL) {
1250 fibril_mutex_unlock(&cdir.mutex);
1251 async_answer_0(&call, ENOMEM);
1252 async_answer_0(icall, ENOMEM);
1253 return;
1254 }
1255
1256 fibril_mutex_lock(&cat->mutex);
1257
1258 rc = category_get_services(cat, id_buf, size, &act_size);
1259 if (rc != EOK) {
1260 fibril_mutex_unlock(&cat->mutex);
1261 fibril_mutex_unlock(&cdir.mutex);
1262 async_answer_0(&call, rc);
1263 async_answer_0(icall, rc);
1264 return;
1265 }
1266
1267 fibril_mutex_unlock(&cat->mutex);
1268 fibril_mutex_unlock(&cdir.mutex);
1269
1270 errno_t retval = async_data_read_finalize(&call, id_buf, size);
1271 free(id_buf);
1272
1273 async_answer_1(icall, retval, act_size);
1274}
1275
1276static void loc_null_create(ipc_call_t *icall)
1277{
1278 fibril_mutex_lock(&null_services_mutex);
1279
1280 unsigned int i;
1281 bool fnd = false;
1282
1283 for (i = 0; i < NULL_SERVICES; i++) {
1284 if (null_services[i] == NULL) {
1285 fnd = true;
1286 break;
1287 }
1288 }
1289
1290 if (!fnd) {
1291 fibril_mutex_unlock(&null_services_mutex);
1292 async_answer_0(icall, ENOMEM);
1293 return;
1294 }
1295
1296 char null[LOC_NAME_MAXLEN];
1297 snprintf(null, LOC_NAME_MAXLEN, "%u", i);
1298
1299 char *dev_name = str_dup(null);
1300 if (dev_name == NULL) {
1301 fibril_mutex_unlock(&null_services_mutex);
1302 async_answer_0(icall, ENOMEM);
1303 return;
1304 }
1305
1306 loc_service_t *service =
1307 (loc_service_t *) malloc(sizeof(loc_service_t));
1308 if (service == NULL) {
1309 fibril_mutex_unlock(&null_services_mutex);
1310 async_answer_0(icall, ENOMEM);
1311 return;
1312 }
1313
1314 fibril_mutex_lock(&services_list_mutex);
1315
1316 loc_namespace_t *namespace = loc_namespace_create("null");
1317 if (namespace == NULL) {
1318 fibril_mutex_lock(&services_list_mutex);
1319 fibril_mutex_unlock(&null_services_mutex);
1320 async_answer_0(icall, ENOMEM);
1321 return;
1322 }
1323
1324 link_initialize(&service->services);
1325 link_initialize(&service->server_services);
1326 list_initialize(&service->cat_memb);
1327
1328 /* Get unique service ID */
1329 service->id = loc_create_id();
1330 service->server = NULL;
1331
1332 loc_namespace_addref(namespace, service);
1333 service->name = dev_name;
1334
1335 /*
1336 * Insert service into list of all services and into null services array.
1337 * Insert service into a dummy list of null server's services so that it
1338 * can be safely removed later.
1339 */
1340 list_append(&service->services, &services_list);
1341 list_append(&service->server_services, &dummy_null_services);
1342 null_services[i] = service;
1343
1344 fibril_mutex_unlock(&services_list_mutex);
1345 fibril_mutex_unlock(&null_services_mutex);
1346
1347 async_answer_1(icall, EOK, (sysarg_t) i);
1348}
1349
1350static void loc_null_destroy(ipc_call_t *icall)
1351{
1352 sysarg_t i = ipc_get_arg1(icall);
1353 if (i >= NULL_SERVICES) {
1354 async_answer_0(icall, ELIMIT);
1355 return;
1356 }
1357
1358 fibril_mutex_lock(&null_services_mutex);
1359
1360 if (null_services[i] == NULL) {
1361 fibril_mutex_unlock(&null_services_mutex);
1362 async_answer_0(icall, ENOENT);
1363 return;
1364 }
1365
1366 fibril_mutex_lock(&services_list_mutex);
1367 fibril_mutex_lock(&cdir.mutex);
1368 loc_service_unregister_core(null_services[i]);
1369 fibril_mutex_unlock(&cdir.mutex);
1370 fibril_mutex_unlock(&services_list_mutex);
1371
1372 null_services[i] = NULL;
1373
1374 fibril_mutex_unlock(&null_services_mutex);
1375 async_answer_0(icall, EOK);
1376}
1377
1378static void loc_service_add_to_cat(ipc_call_t *icall)
1379{
1380 category_t *cat;
1381 loc_service_t *svc;
1382 catid_t cat_id;
1383 service_id_t svc_id;
1384 errno_t retval;
1385
1386 svc_id = ipc_get_arg1(icall);
1387 cat_id = ipc_get_arg2(icall);
1388
1389 fibril_mutex_lock(&services_list_mutex);
1390 fibril_mutex_lock(&cdir.mutex);
1391
1392 cat = category_get(&cdir, cat_id);
1393 svc = loc_service_find_id(svc_id);
1394
1395 if (cat == NULL || svc == NULL) {
1396 fibril_mutex_unlock(&cdir.mutex);
1397 fibril_mutex_unlock(&services_list_mutex);
1398 async_answer_0(icall, ENOENT);
1399 return;
1400 }
1401
1402 fibril_mutex_lock(&cat->mutex);
1403 retval = category_add_service(cat, svc);
1404
1405 fibril_mutex_unlock(&cat->mutex);
1406 fibril_mutex_unlock(&cdir.mutex);
1407 fibril_mutex_unlock(&services_list_mutex);
1408
1409 /*
1410 * First send out all notifications and only then answer the request.
1411 * Otherwise the current fibril might block and transitively wait for
1412 * the completion of requests that are routed to it via an IPC loop.
1413 */
1414 loc_category_change_event();
1415 async_answer_0(icall, retval);
1416}
1417
1418/** Initialize location service.
1419 *
1420 *
1421 */
1422static bool loc_init(void)
1423{
1424 unsigned int i;
1425 category_t *cat;
1426
1427 for (i = 0; i < NULL_SERVICES; i++)
1428 null_services[i] = NULL;
1429
1430 categ_dir_init(&cdir);
1431
1432 cat = category_new("disk");
1433 categ_dir_add_cat(&cdir, cat);
1434
1435 cat = category_new("partition");
1436 categ_dir_add_cat(&cdir, cat);
1437
1438 cat = category_new("iplink");
1439 categ_dir_add_cat(&cdir, cat);
1440
1441 cat = category_new("keyboard");
1442 categ_dir_add_cat(&cdir, cat);
1443
1444 cat = category_new("mouse");
1445 categ_dir_add_cat(&cdir, cat);
1446
1447 cat = category_new("led");
1448 categ_dir_add_cat(&cdir, cat);
1449
1450 cat = category_new("serial");
1451 categ_dir_add_cat(&cdir, cat);
1452
1453 cat = category_new("console");
1454 categ_dir_add_cat(&cdir, cat);
1455
1456 cat = category_new("clock");
1457 categ_dir_add_cat(&cdir, cat);
1458
1459 cat = category_new("test3");
1460 categ_dir_add_cat(&cdir, cat);
1461
1462 cat = category_new("usbdiag");
1463 categ_dir_add_cat(&cdir, cat);
1464
1465 cat = category_new("usbhc");
1466 categ_dir_add_cat(&cdir, cat);
1467
1468 cat = category_new("virt-null");
1469 categ_dir_add_cat(&cdir, cat);
1470
1471 cat = category_new("virtual");
1472 categ_dir_add_cat(&cdir, cat);
1473
1474 cat = category_new("nic");
1475 categ_dir_add_cat(&cdir, cat);
1476
1477 cat = category_new("ieee80211");
1478 categ_dir_add_cat(&cdir, cat);
1479
1480 cat = category_new("irc");
1481 categ_dir_add_cat(&cdir, cat);
1482
1483 cat = category_new("visualizer");
1484 categ_dir_add_cat(&cdir, cat);
1485
1486 cat = category_new("renderer");
1487 categ_dir_add_cat(&cdir, cat);
1488
1489 cat = category_new("audio-pcm");
1490 categ_dir_add_cat(&cdir, cat);
1491
1492 cat = category_new("printer-port");
1493 categ_dir_add_cat(&cdir, cat);
1494
1495 cat = category_new("pci");
1496 categ_dir_add_cat(&cdir, cat);
1497
1498 return true;
1499}
1500
1501/** Handle connection on supplier port.
1502 *
1503 */
1504static void loc_connection_supplier(ipc_call_t *icall, void *arg)
1505{
1506 /* Accept connection */
1507 async_accept_0(icall);
1508
1509 /*
1510 * Each connection begins by a LOC_SERVER_REGISTER, which precludes us
1511 * from using parallel exchanges.
1512 */
1513 static_assert((INTERFACE_LOC_SUPPLIER & IFACE_EXCHANGE_MASK) ==
1514 IFACE_EXCHANGE_SERIALIZE, "");
1515
1516 loc_server_t *server = loc_server_register();
1517 if (server == NULL)
1518 return;
1519
1520 while (true) {
1521 ipc_call_t call;
1522 async_get_call(&call);
1523
1524 if (!ipc_get_imethod(&call)) {
1525 async_answer_0(&call, EOK);
1526 break;
1527 }
1528
1529 switch (ipc_get_imethod(&call)) {
1530 case LOC_SERVER_UNREGISTER:
1531 if (server == NULL)
1532 async_answer_0(&call, ENOENT);
1533 else
1534 async_answer_0(&call, EOK);
1535 break;
1536 case LOC_SERVICE_ADD_TO_CAT:
1537 /* Add service to category */
1538 loc_service_add_to_cat(&call);
1539 break;
1540 case LOC_SERVICE_REGISTER:
1541 /* Register one service */
1542 loc_service_register(&call, server);
1543 break;
1544 case LOC_SERVICE_UNREGISTER:
1545 /* Remove one service */
1546 loc_service_unregister(&call, server);
1547 break;
1548 case LOC_SERVICE_GET_ID:
1549 loc_service_get_id(&call);
1550 break;
1551 case LOC_NAMESPACE_GET_ID:
1552 loc_namespace_get_id(&call);
1553 break;
1554 default:
1555 async_answer_0(&call, ENOENT);
1556 }
1557 }
1558
1559 if (server != NULL) {
1560 /*
1561 * Unregister the server and all its services.
1562 */
1563 loc_server_unregister(server);
1564 server = NULL;
1565 }
1566}
1567
1568/** Handle connection on consumer port.
1569 *
1570 */
1571static void loc_connection_consumer(ipc_call_t *icall, void *arg)
1572{
1573 /* Accept connection */
1574 async_accept_0(icall);
1575
1576 while (true) {
1577 ipc_call_t call;
1578 async_get_call(&call);
1579
1580 if (!ipc_get_imethod(&call)) {
1581 async_answer_0(&call, EOK);
1582 break;
1583 }
1584
1585 switch (ipc_get_imethod(&call)) {
1586 case LOC_SERVICE_GET_ID:
1587 loc_service_get_id(&call);
1588 break;
1589 case LOC_SERVICE_GET_NAME:
1590 loc_service_get_name(&call);
1591 break;
1592 case LOC_SERVICE_GET_SERVER_NAME:
1593 loc_service_get_server_name(&call);
1594 break;
1595 case LOC_NAMESPACE_GET_ID:
1596 loc_namespace_get_id(&call);
1597 break;
1598 case LOC_CALLBACK_CREATE:
1599 loc_callback_create(&call);
1600 break;
1601 case LOC_CATEGORY_GET_ID:
1602 loc_category_get_id(&call);
1603 break;
1604 case LOC_CATEGORY_GET_NAME:
1605 loc_category_get_name(&call);
1606 break;
1607 case LOC_CATEGORY_GET_SVCS:
1608 loc_category_get_svcs(&call);
1609 break;
1610 case LOC_ID_PROBE:
1611 loc_id_probe(&call);
1612 break;
1613 case LOC_NULL_CREATE:
1614 loc_null_create(&call);
1615 break;
1616 case LOC_NULL_DESTROY:
1617 loc_null_destroy(&call);
1618 break;
1619 case LOC_GET_NAMESPACE_COUNT:
1620 loc_get_namespace_count(&call);
1621 break;
1622 case LOC_GET_SERVICE_COUNT:
1623 loc_get_service_count(&call);
1624 break;
1625 case LOC_GET_CATEGORIES:
1626 loc_get_categories(&call);
1627 break;
1628 case LOC_GET_NAMESPACES:
1629 loc_get_namespaces(&call);
1630 break;
1631 case LOC_GET_SERVICES:
1632 loc_get_services(&call);
1633 break;
1634 default:
1635 async_answer_0(&call, ENOENT);
1636 }
1637 }
1638}
1639
1640/**
1641 *
1642 */
1643int main(int argc, char *argv[])
1644{
1645 printf("%s: HelenOS Location Service\n", NAME);
1646
1647 if (!loc_init()) {
1648 printf("%s: Error while initializing service\n", NAME);
1649 return -1;
1650 }
1651
1652 /* Register location service at naming service */
1653 errno_t rc = service_register(SERVICE_LOC, INTERFACE_LOC_SUPPLIER,
1654 loc_connection_supplier, NULL);
1655 if (rc != EOK) {
1656 printf("%s: Error while registering supplier service: %s\n", NAME, str_error(rc));
1657 return rc;
1658 }
1659
1660 rc = service_register(SERVICE_LOC, INTERFACE_LOC_CONSUMER,
1661 loc_connection_consumer, NULL);
1662 if (rc != EOK) {
1663 printf("%s: Error while registering consumer service: %s\n", NAME, str_error(rc));
1664 return rc;
1665 }
1666
1667 rc = service_register_broker(SERVICE_LOC, loc_forward, NULL);
1668 if (rc != EOK) {
1669 printf("%s: Error while registering broker service: %s\n", NAME, str_error(rc));
1670
1671 /* Let sysman know we are broker */
1672 rc = sysman_broker_register();
1673 if (rc != EOK) {
1674 printf("%s: Error registering at sysman (%i)\n", NAME, rc);
1675 return rc;
1676 }
1677
1678 printf("%s: Accepting connections\n", NAME);
1679 async_manager();
1680
1681 /* Never reached */
1682 return 0;
1683}
1684
1685/**
1686 * @}
1687 */
Note: See TracBrowser for help on using the repository browser.