source: mainline/uspace/srv/locsrv/locsrv.c@ 777832e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 777832e was 7c3fb9b, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Fix block comment formatting (ccheck).

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