source: mainline/uspace/srv/locsrv/locsrv.c@ 498ced1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 498ced1 was 9b1baac, checked in by Martin Decky <martin@…>, 7 years ago

ns: register service interfaces individually

Each service interface is now registered individually with the naming
service. This adds a degree of type safety, potentially allows the
individual interfaces to be implemented by independent tasks and moves
the code slightly closer to the full-fledged ports design.

Broker services (e.g. the location service) can still register a
fallback port for receiving connections to all interface types
explicitly using service_register_broker().

  • Property mode set to 100644
File size: 34.7 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;
[984a9ba]343 async_get_call(&icall);
[a35b458]344
[15f3c3f]345 if (IPC_GET_IMETHOD(icall) != LOC_SERVER_REGISTER) {
[984a9ba]346 async_answer_0(&icall, 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) {
[984a9ba]353 async_answer_0(&icall, 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);
[984a9ba]364 async_answer_0(&icall, 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);
[984a9ba]375 async_answer_0(&icall, 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
[984a9ba]405 async_answer_0(&icall, 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 */
[984a9ba]458static void loc_service_register(ipc_call_t *icall, loc_server_t *server)
[15f3c3f]459{
460 if (server == NULL) {
[984a9ba]461 async_answer_0(icall, EREFUSED);
[15f3c3f]462 return;
463 }
[a35b458]464
[15f3c3f]465 /* Create new service entry */
466 loc_service_t *service =
467 (loc_service_t *) malloc(sizeof(loc_service_t));
468 if (service == NULL) {
[984a9ba]469 async_answer_0(icall, ENOMEM);
[15f3c3f]470 return;
471 }
[a35b458]472
[15f3c3f]473 /* Get fqsn */
474 char *fqsn;
[5a6cc679]475 errno_t rc = async_data_write_accept((void **) &fqsn, true, 0,
[15f3c3f]476 LOC_NAME_MAXLEN, 0, NULL);
477 if (rc != EOK) {
478 free(service);
[984a9ba]479 async_answer_0(icall, rc);
[15f3c3f]480 return;
481 }
[a35b458]482
[15f3c3f]483 char *ns_name;
484 if (!loc_fqsn_split(fqsn, &ns_name, &service->name)) {
485 free(fqsn);
486 free(service);
[984a9ba]487 async_answer_0(icall, EINVAL);
[15f3c3f]488 return;
489 }
[a35b458]490
[15f3c3f]491 free(fqsn);
[a35b458]492
[15f3c3f]493 fibril_mutex_lock(&services_list_mutex);
[a35b458]494
[15f3c3f]495 loc_namespace_t *namespace = loc_namespace_create(ns_name);
496 free(ns_name);
497 if (namespace == NULL) {
498 fibril_mutex_unlock(&services_list_mutex);
499 free(service->name);
500 free(service);
[984a9ba]501 async_answer_0(icall, ENOMEM);
[15f3c3f]502 return;
503 }
[a35b458]504
[15f3c3f]505 link_initialize(&service->services);
506 link_initialize(&service->server_services);
[d0dd7b5]507 list_initialize(&service->cat_memb);
[a35b458]508
[15f3c3f]509 /* Check that service is not already registered */
510 if (loc_service_find_name(namespace->name, service->name) != NULL) {
511 printf("%s: Service '%s/%s' already registered\n", NAME,
512 namespace->name, service->name);
513 loc_namespace_destroy(namespace);
514 fibril_mutex_unlock(&services_list_mutex);
515 free(service->name);
516 free(service);
[984a9ba]517 async_answer_0(icall, EEXIST);
[15f3c3f]518 return;
519 }
[a35b458]520
[15f3c3f]521 /* Get unique service ID */
522 service->id = loc_create_id();
523
524 loc_namespace_addref(namespace, service);
525 service->server = server;
[a35b458]526
[15f3c3f]527 /* Insert service into list of all services */
528 list_append(&service->services, &services_list);
[a35b458]529
[15f3c3f]530 /* Insert service into list of services supplied by one server */
531 fibril_mutex_lock(&service->server->services_mutex);
[a35b458]532
[15f3c3f]533 list_append(&service->server_services, &service->server->services);
[a35b458]534
[15f3c3f]535 fibril_mutex_unlock(&service->server->services_mutex);
536 fibril_condvar_broadcast(&services_list_cv);
537 fibril_mutex_unlock(&services_list_mutex);
[a35b458]538
[984a9ba]539 async_answer_1(icall, EOK, service->id);
[15f3c3f]540}
541
542/**
543 *
544 */
[984a9ba]545static void loc_service_unregister(ipc_call_t *icall, loc_server_t *server)
[15f3c3f]546{
[d0dd7b5]547 loc_service_t *svc;
[a35b458]548
[d0dd7b5]549 fibril_mutex_lock(&services_list_mutex);
550 svc = loc_service_find_id(IPC_GET_ARG1(*icall));
551 if (svc == NULL) {
552 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]553 async_answer_0(icall, ENOENT);
[d0dd7b5]554 return;
555 }
[a35b458]556
[d0dd7b5]557 fibril_mutex_lock(&cdir.mutex);
558 loc_service_unregister_core(svc);
559 fibril_mutex_unlock(&cdir.mutex);
560 fibril_mutex_unlock(&services_list_mutex);
[3a9cf35]561
[adb1ae9]562 /*
563 * First send out all notifications and only then answer the request.
564 * Otherwise the current fibril might block and transitively wait for
565 * the completion of requests that are routed to it via an IPC loop.
566 */
[3a9cf35]567 loc_category_change_event();
[984a9ba]568 async_answer_0(icall, EOK);
[15f3c3f]569}
570
[984a9ba]571static void loc_category_get_name(ipc_call_t *icall)
[763e0cd]572{
[984a9ba]573 ipc_call_t call;
[763e0cd]574 size_t size;
575 size_t act_size;
576 category_t *cat;
[a35b458]577
[984a9ba]578 if (!async_data_read_receive(&call, &size)) {
579 async_answer_0(&call, EREFUSED);
580 async_answer_0(icall, EREFUSED);
[763e0cd]581 return;
582 }
[a35b458]583
[763e0cd]584 fibril_mutex_lock(&cdir.mutex);
[a35b458]585
[763e0cd]586 cat = category_get(&cdir, IPC_GET_ARG1(*icall));
587 if (cat == NULL) {
588 fibril_mutex_unlock(&cdir.mutex);
[984a9ba]589 async_answer_0(&call, ENOENT);
590 async_answer_0(icall, ENOENT);
[763e0cd]591 return;
592 }
[a35b458]593
[763e0cd]594 act_size = str_size(cat->name);
595 if (act_size > size) {
596 fibril_mutex_unlock(&cdir.mutex);
[984a9ba]597 async_answer_0(&call, EOVERFLOW);
598 async_answer_0(icall, EOVERFLOW);
[763e0cd]599 return;
600 }
[a35b458]601
[984a9ba]602 errno_t retval = async_data_read_finalize(&call, cat->name,
[763e0cd]603 min(size, act_size));
[a35b458]604
[763e0cd]605 fibril_mutex_unlock(&cdir.mutex);
[a35b458]606
[984a9ba]607 async_answer_0(icall, retval);
[763e0cd]608}
609
[984a9ba]610static void loc_service_get_name(ipc_call_t *icall)
[cce8a83]611{
[984a9ba]612 ipc_call_t call;
[cce8a83]613 size_t size;
614 size_t act_size;
615 loc_service_t *svc;
[77a69ea]616 char *fqn;
[a35b458]617
[984a9ba]618 if (!async_data_read_receive(&call, &size)) {
619 async_answer_0(&call, EREFUSED);
620 async_answer_0(icall, EREFUSED);
[cce8a83]621 return;
622 }
[a35b458]623
[cce8a83]624 fibril_mutex_lock(&services_list_mutex);
[a35b458]625
[cce8a83]626 svc = loc_service_find_id(IPC_GET_ARG1(*icall));
627 if (svc == NULL) {
628 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]629 async_answer_0(&call, ENOENT);
630 async_answer_0(icall, ENOENT);
[cce8a83]631 return;
632 }
[a35b458]633
[77a69ea]634 if (asprintf(&fqn, "%s/%s", svc->namespace->name, svc->name) < 0) {
635 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]636 async_answer_0(&call, ENOMEM);
637 async_answer_0(icall, ENOMEM);
[77a69ea]638 return;
639 }
[a35b458]640
[77a69ea]641 act_size = str_size(fqn);
[cce8a83]642 if (act_size > size) {
[77a69ea]643 free(fqn);
[cce8a83]644 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]645 async_answer_0(&call, EOVERFLOW);
646 async_answer_0(icall, EOVERFLOW);
[cce8a83]647 return;
648 }
[a35b458]649
[984a9ba]650 errno_t retval = async_data_read_finalize(&call, fqn,
[cce8a83]651 min(size, act_size));
[77a69ea]652 free(fqn);
[a35b458]653
[cce8a83]654 fibril_mutex_unlock(&services_list_mutex);
[a35b458]655
[984a9ba]656 async_answer_0(icall, retval);
[cce8a83]657}
658
[984a9ba]659static void loc_service_get_server_name(ipc_call_t *icall)
[a3fcfba]660{
[984a9ba]661 ipc_call_t call;
[a3fcfba]662 size_t size;
663 size_t act_size;
664 loc_service_t *svc;
[a35b458]665
[984a9ba]666 if (!async_data_read_receive(&call, &size)) {
667 async_answer_0(&call, EREFUSED);
668 async_answer_0(icall, EREFUSED);
[a3fcfba]669 return;
670 }
[a35b458]671
[a3fcfba]672 fibril_mutex_lock(&services_list_mutex);
[a35b458]673
[a3fcfba]674 svc = loc_service_find_id(IPC_GET_ARG1(*icall));
675 if (svc == NULL) {
676 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]677 async_answer_0(&call, ENOENT);
678 async_answer_0(icall, ENOENT);
[a3fcfba]679 return;
680 }
[a35b458]681
[a3fcfba]682 if (svc->server == NULL) {
683 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]684 async_answer_0(&call, EINVAL);
685 async_answer_0(icall, EINVAL);
[a3fcfba]686 return;
687 }
[a35b458]688
[a3fcfba]689 act_size = str_size(svc->server->name);
690 if (act_size > size) {
691 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]692 async_answer_0(&call, EOVERFLOW);
693 async_answer_0(icall, EOVERFLOW);
[a3fcfba]694 return;
695 }
[a35b458]696
[984a9ba]697 errno_t retval = async_data_read_finalize(&call, svc->server->name,
[a3fcfba]698 min(size, act_size));
[a35b458]699
[a3fcfba]700 fibril_mutex_unlock(&services_list_mutex);
[a35b458]701
[984a9ba]702 async_answer_0(icall, retval);
[a3fcfba]703}
704
[15f3c3f]705/** Connect client to the service.
706 *
707 * Find server supplying requested service and forward
708 * the message to it.
709 *
710 */
[984a9ba]711static void loc_forward(ipc_call_t *call, void *arg)
[15f3c3f]712{
713 fibril_mutex_lock(&services_list_mutex);
[a35b458]714
[15f3c3f]715 /*
716 * Get ID from request
717 */
[f9b2cb4c]718 iface_t iface = IPC_GET_ARG1(*call);
[15f3c3f]719 service_id_t id = IPC_GET_ARG2(*call);
720 loc_service_t *svc = loc_service_find_id(id);
[a35b458]721
[15f3c3f]722 if ((svc == NULL) || (svc->server == NULL) || (!svc->server->sess)) {
723 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]724 async_answer_0(call, ENOENT);
[15f3c3f]725 return;
726 }
[a35b458]727
[15f3c3f]728 async_exch_t *exch = async_exchange_begin(svc->server->sess);
[984a9ba]729 async_forward_fast(call, exch, iface, svc->id, 0, IPC_FF_NONE);
[15f3c3f]730 async_exchange_end(exch);
[a35b458]731
[15f3c3f]732 fibril_mutex_unlock(&services_list_mutex);
733}
734
735/** Find ID for service identified by name.
736 *
737 * In answer will be send EOK and service ID in arg1 or a error
738 * code from errno.h.
739 *
740 */
[984a9ba]741static void loc_service_get_id(ipc_call_t *icall)
[15f3c3f]742{
743 char *fqsn;
[a35b458]744
[15f3c3f]745 /* Get fqsn */
[5a6cc679]746 errno_t rc = async_data_write_accept((void **) &fqsn, true, 0,
[15f3c3f]747 LOC_NAME_MAXLEN, 0, NULL);
748 if (rc != EOK) {
[984a9ba]749 async_answer_0(icall, rc);
[15f3c3f]750 return;
751 }
[a35b458]752
[15f3c3f]753 char *ns_name;
754 char *name;
755 if (!loc_fqsn_split(fqsn, &ns_name, &name)) {
756 free(fqsn);
[984a9ba]757 async_answer_0(icall, EINVAL);
[15f3c3f]758 return;
759 }
[a35b458]760
[15f3c3f]761 free(fqsn);
[a35b458]762
[15f3c3f]763 fibril_mutex_lock(&services_list_mutex);
764 const loc_service_t *svc;
[a35b458]765
[15f3c3f]766recheck:
[a35b458]767
[15f3c3f]768 /*
769 * Find service name in the list of known services.
770 */
771 svc = loc_service_find_name(ns_name, name);
[a35b458]772
[15f3c3f]773 /*
774 * Device was not found.
775 */
776 if (svc == NULL) {
777 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
778 /* Blocking lookup */
779 fibril_condvar_wait(&services_list_cv,
780 &services_list_mutex);
781 goto recheck;
782 }
[a35b458]783
[984a9ba]784 async_answer_0(icall, ENOENT);
[15f3c3f]785 free(ns_name);
786 free(name);
787 fibril_mutex_unlock(&services_list_mutex);
788 return;
789 }
[a35b458]790
[984a9ba]791 async_answer_1(icall, EOK, svc->id);
[a35b458]792
[15f3c3f]793 fibril_mutex_unlock(&services_list_mutex);
794 free(ns_name);
795 free(name);
796}
797
798/** Find ID for namespace identified by name.
799 *
800 * In answer will be send EOK and service ID in arg1 or a error
801 * code from errno.h.
802 *
803 */
[984a9ba]804static void loc_namespace_get_id(ipc_call_t *icall)
[15f3c3f]805{
806 char *name;
[a35b458]807
[15f3c3f]808 /* Get service name */
[5a6cc679]809 errno_t rc = async_data_write_accept((void **) &name, true, 0,
[15f3c3f]810 LOC_NAME_MAXLEN, 0, NULL);
811 if (rc != EOK) {
[984a9ba]812 async_answer_0(icall, rc);
[15f3c3f]813 return;
814 }
[a35b458]815
[15f3c3f]816 fibril_mutex_lock(&services_list_mutex);
817 const loc_namespace_t *namespace;
[a35b458]818
[15f3c3f]819recheck:
[a35b458]820
[15f3c3f]821 /*
822 * Find namespace name in the list of known namespaces.
823 */
824 namespace = loc_namespace_find_name(name);
[a35b458]825
[15f3c3f]826 /*
827 * Namespace was not found.
828 */
829 if (namespace == NULL) {
830 if (IPC_GET_ARG1(*icall) & IPC_FLAG_BLOCKING) {
831 /* Blocking lookup */
832 fibril_condvar_wait(&services_list_cv,
833 &services_list_mutex);
834 goto recheck;
835 }
[a35b458]836
[984a9ba]837 async_answer_0(icall, ENOENT);
[15f3c3f]838 free(name);
839 fibril_mutex_unlock(&services_list_mutex);
840 return;
841 }
[a35b458]842
[984a9ba]843 async_answer_1(icall, EOK, namespace->id);
[a35b458]844
[15f3c3f]845 fibril_mutex_unlock(&services_list_mutex);
846 free(name);
847}
848
[77a69ea]849/** Create callback connection.
[12f9f0d0]850 *
[77a69ea]851 * Create callback connection which will be used to send category change
852 * events.
[12f9f0d0]853 *
[5a6cc679]854 * On success, answer will contain EOK errno_t retval.
[77a69ea]855 * On failure, error code will be sent in retval.
[5cc9eba]856 *
[12f9f0d0]857 */
[984a9ba]858static void loc_callback_create(ipc_call_t *icall)
[12f9f0d0]859{
[5cc9eba]860 cb_sess_t *cb_sess = calloc(1, sizeof(cb_sess_t));
[12f9f0d0]861 if (cb_sess == NULL) {
[984a9ba]862 async_answer_0(icall, ENOMEM);
[12f9f0d0]863 return;
864 }
[a35b458]865
[77a69ea]866 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
867 if (sess == NULL) {
868 free(cb_sess);
[984a9ba]869 async_answer_0(icall, ENOMEM);
[12f9f0d0]870 return;
871 }
[a35b458]872
[77a69ea]873 cb_sess->sess = sess;
874 link_initialize(&cb_sess->cb_sess_list);
[a35b458]875
[77a69ea]876 fibril_mutex_lock(&callback_sess_mutex);
877 list_append(&cb_sess->cb_sess_list, &callback_sess_list);
[12f9f0d0]878 fibril_mutex_unlock(&callback_sess_mutex);
[a35b458]879
[984a9ba]880 async_answer_0(icall, EOK);
[12f9f0d0]881}
882
883void loc_category_change_event(void)
884{
885 fibril_mutex_lock(&callback_sess_mutex);
[a35b458]886
[feeac0d]887 list_foreach(callback_sess_list, cb_sess_list, cb_sess_t, cb_sess) {
[77a69ea]888 async_exch_t *exch = async_exchange_begin(cb_sess->sess);
[12f9f0d0]889 async_msg_0(exch, LOC_EVENT_CAT_CHANGE);
890 async_exchange_end(exch);
891 }
[a35b458]892
[12f9f0d0]893 fibril_mutex_unlock(&callback_sess_mutex);
894}
895
[cc574511]896/** Find ID for category specified by name.
897 *
[5a6cc679]898 * On success, answer will contain EOK errno_t retval and service ID in arg1.
[cc574511]899 * On failure, error code will be sent in retval.
900 *
901 */
[984a9ba]902static void loc_category_get_id(ipc_call_t *icall)
[cc574511]903{
904 char *name;
905 category_t *cat;
[a35b458]906
[cc574511]907 /* Get service name */
[5a6cc679]908 errno_t rc = async_data_write_accept((void **) &name, true, 0,
[cc574511]909 LOC_NAME_MAXLEN, 0, NULL);
910 if (rc != EOK) {
[984a9ba]911 async_answer_0(icall, rc);
[cc574511]912 return;
913 }
[a35b458]914
[cc574511]915 fibril_mutex_lock(&cdir.mutex);
916
917 cat = category_find_by_name(&cdir, name);
918 if (cat == NULL) {
919 /* Category not found */
[984a9ba]920 async_answer_0(icall, ENOENT);
[cc574511]921 goto cleanup;
922 }
[a35b458]923
[984a9ba]924 async_answer_1(icall, EOK, cat->id);
[cc574511]925cleanup:
926 fibril_mutex_unlock(&cdir.mutex);
927 free(name);
928}
929
[984a9ba]930static void loc_id_probe(ipc_call_t *icall)
[15f3c3f]931{
932 fibril_mutex_lock(&services_list_mutex);
[a35b458]933
[15f3c3f]934 loc_namespace_t *namespace =
935 loc_namespace_find_id(IPC_GET_ARG1(*icall));
936 if (namespace == NULL) {
937 loc_service_t *svc =
938 loc_service_find_id(IPC_GET_ARG1(*icall));
939 if (svc == NULL)
[984a9ba]940 async_answer_1(icall, EOK, LOC_OBJECT_NONE);
[15f3c3f]941 else
[984a9ba]942 async_answer_1(icall, EOK, LOC_OBJECT_SERVICE);
[15f3c3f]943 } else
[984a9ba]944 async_answer_1(icall, EOK, LOC_OBJECT_NAMESPACE);
[a35b458]945
[15f3c3f]946 fibril_mutex_unlock(&services_list_mutex);
947}
948
[984a9ba]949static void loc_get_namespace_count(ipc_call_t *icall)
[15f3c3f]950{
951 fibril_mutex_lock(&services_list_mutex);
[984a9ba]952 async_answer_1(icall, EOK, list_count(&namespaces_list));
[15f3c3f]953 fibril_mutex_unlock(&services_list_mutex);
954}
955
[984a9ba]956static void loc_get_service_count(ipc_call_t *icall)
[15f3c3f]957{
958 fibril_mutex_lock(&services_list_mutex);
[a35b458]959
[15f3c3f]960 loc_namespace_t *namespace =
961 loc_namespace_find_id(IPC_GET_ARG1(*icall));
962 if (namespace == NULL)
[984a9ba]963 async_answer_0(icall, EEXIST);
[15f3c3f]964 else
[984a9ba]965 async_answer_1(icall, EOK, namespace->refcnt);
[a35b458]966
[15f3c3f]967 fibril_mutex_unlock(&services_list_mutex);
968}
969
[984a9ba]970static void loc_get_categories(ipc_call_t *icall)
[278ac72]971{
[984a9ba]972 ipc_call_t call;
[278ac72]973 size_t size;
974 size_t act_size;
[5a6cc679]975 errno_t rc;
[a35b458]976
[984a9ba]977 if (!async_data_read_receive(&call, &size)) {
978 async_answer_0(&call, EREFUSED);
979 async_answer_0(icall, EREFUSED);
[278ac72]980 return;
981 }
[a35b458]982
[278ac72]983 category_id_t *id_buf = (category_id_t *) malloc(size);
984 if (id_buf == NULL) {
985 fibril_mutex_unlock(&cdir.mutex);
[984a9ba]986 async_answer_0(&call, ENOMEM);
987 async_answer_0(icall, ENOMEM);
[278ac72]988 return;
989 }
[a35b458]990
[278ac72]991 fibril_mutex_lock(&cdir.mutex);
[a35b458]992
[278ac72]993 rc = categ_dir_get_categories(&cdir, id_buf, size, &act_size);
994 if (rc != EOK) {
995 fibril_mutex_unlock(&cdir.mutex);
[984a9ba]996 async_answer_0(&call, rc);
997 async_answer_0(icall, rc);
[278ac72]998 return;
999 }
[a35b458]1000
[278ac72]1001 fibril_mutex_unlock(&cdir.mutex);
[a35b458]1002
[984a9ba]1003 errno_t retval = async_data_read_finalize(&call, id_buf, size);
[278ac72]1004 free(id_buf);
[a35b458]1005
[984a9ba]1006 async_answer_1(icall, retval, act_size);
[278ac72]1007}
1008
[984a9ba]1009static void loc_get_namespaces(ipc_call_t *icall)
[15f3c3f]1010{
[984a9ba]1011 ipc_call_t call;
[15f3c3f]1012 size_t size;
[984a9ba]1013 if (!async_data_read_receive(&call, &size)) {
1014 async_answer_0(&call, EREFUSED);
1015 async_answer_0(icall, EREFUSED);
[15f3c3f]1016 return;
1017 }
[a35b458]1018
[15f3c3f]1019 if ((size % sizeof(loc_sdesc_t)) != 0) {
[984a9ba]1020 async_answer_0(&call, EINVAL);
1021 async_answer_0(icall, EINVAL);
[15f3c3f]1022 return;
1023 }
[a35b458]1024
[15f3c3f]1025 fibril_mutex_lock(&services_list_mutex);
[a35b458]1026
[15f3c3f]1027 size_t count = size / sizeof(loc_sdesc_t);
1028 if (count != list_count(&namespaces_list)) {
1029 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]1030 async_answer_0(&call, EOVERFLOW);
1031 async_answer_0(icall, EOVERFLOW);
[15f3c3f]1032 return;
1033 }
[a35b458]1034
[15f3c3f]1035 loc_sdesc_t *desc = (loc_sdesc_t *) malloc(size);
1036 if (desc == NULL) {
1037 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]1038 async_answer_0(&call, ENOMEM);
1039 async_answer_0(icall, ENOMEM);
[15f3c3f]1040 return;
1041 }
[a35b458]1042
[15f3c3f]1043 size_t pos = 0;
[feeac0d]1044 list_foreach(namespaces_list, namespaces, loc_namespace_t, namespace) {
[15f3c3f]1045 desc[pos].id = namespace->id;
1046 str_cpy(desc[pos].name, LOC_NAME_MAXLEN, namespace->name);
1047 pos++;
1048 }
[a35b458]1049
[984a9ba]1050 errno_t retval = async_data_read_finalize(&call, desc, size);
[a35b458]1051
[15f3c3f]1052 free(desc);
1053 fibril_mutex_unlock(&services_list_mutex);
[a35b458]1054
[984a9ba]1055 async_answer_0(icall, retval);
[15f3c3f]1056}
1057
[984a9ba]1058static void loc_get_services(ipc_call_t *icall)
[15f3c3f]1059{
[7c3fb9b]1060 /*
1061 * FIXME: Use faster algorithm which can make better use
1062 * of namespaces
1063 */
[a35b458]1064
[984a9ba]1065 ipc_call_t call;
[15f3c3f]1066 size_t size;
[984a9ba]1067 if (!async_data_read_receive(&call, &size)) {
1068 async_answer_0(&call, EREFUSED);
1069 async_answer_0(icall, EREFUSED);
[15f3c3f]1070 return;
1071 }
[a35b458]1072
[15f3c3f]1073 if ((size % sizeof(loc_sdesc_t)) != 0) {
[984a9ba]1074 async_answer_0(&call, EINVAL);
1075 async_answer_0(icall, EINVAL);
[15f3c3f]1076 return;
1077 }
[a35b458]1078
[15f3c3f]1079 fibril_mutex_lock(&services_list_mutex);
[a35b458]1080
[15f3c3f]1081 loc_namespace_t *namespace =
1082 loc_namespace_find_id(IPC_GET_ARG1(*icall));
1083 if (namespace == NULL) {
1084 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]1085 async_answer_0(&call, ENOENT);
1086 async_answer_0(icall, ENOENT);
[15f3c3f]1087 return;
1088 }
[a35b458]1089
[15f3c3f]1090 size_t count = size / sizeof(loc_sdesc_t);
1091 if (count != namespace->refcnt) {
1092 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]1093 async_answer_0(&call, EOVERFLOW);
1094 async_answer_0(icall, EOVERFLOW);
[15f3c3f]1095 return;
1096 }
[a35b458]1097
[15f3c3f]1098 loc_sdesc_t *desc = (loc_sdesc_t *) malloc(size);
1099 if (desc == NULL) {
1100 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]1101 async_answer_0(&call, ENOMEM);
1102 async_answer_0(icall, EREFUSED);
[15f3c3f]1103 return;
1104 }
[a35b458]1105
[15f3c3f]1106 size_t pos = 0;
[feeac0d]1107 list_foreach(services_list, services, loc_service_t, service) {
[15f3c3f]1108 if (service->namespace == namespace) {
1109 desc[pos].id = service->id;
1110 str_cpy(desc[pos].name, LOC_NAME_MAXLEN, service->name);
1111 pos++;
1112 }
1113 }
[a35b458]1114
[984a9ba]1115 errno_t retval = async_data_read_finalize(&call, desc, size);
[a35b458]1116
[15f3c3f]1117 free(desc);
1118 fibril_mutex_unlock(&services_list_mutex);
[a35b458]1119
[984a9ba]1120 async_answer_0(icall, retval);
[15f3c3f]1121}
1122
[984a9ba]1123static void loc_category_get_svcs(ipc_call_t *icall)
[cc574511]1124{
[984a9ba]1125 ipc_call_t call;
[cc574511]1126 size_t size;
1127 size_t act_size;
[5a6cc679]1128 errno_t rc;
[a35b458]1129
[984a9ba]1130 if (!async_data_read_receive(&call, &size)) {
1131 async_answer_0(&call, EREFUSED);
1132 async_answer_0(icall, EREFUSED);
[cc574511]1133 return;
1134 }
[a35b458]1135
[cc574511]1136 fibril_mutex_lock(&cdir.mutex);
[a35b458]1137
[cc574511]1138 category_t *cat = category_get(&cdir, IPC_GET_ARG1(*icall));
1139 if (cat == NULL) {
1140 fibril_mutex_unlock(&cdir.mutex);
[984a9ba]1141 async_answer_0(&call, ENOENT);
1142 async_answer_0(icall, ENOENT);
[cc574511]1143 return;
1144 }
[a35b458]1145
[cc574511]1146 category_id_t *id_buf = (category_id_t *) malloc(size);
1147 if (id_buf == NULL) {
1148 fibril_mutex_unlock(&cdir.mutex);
[984a9ba]1149 async_answer_0(&call, ENOMEM);
1150 async_answer_0(icall, ENOMEM);
[cc574511]1151 return;
1152 }
[a35b458]1153
[cc574511]1154 fibril_mutex_lock(&cat->mutex);
[a35b458]1155
[cc574511]1156 rc = category_get_services(cat, id_buf, size, &act_size);
1157 if (rc != EOK) {
1158 fibril_mutex_unlock(&cat->mutex);
1159 fibril_mutex_unlock(&cdir.mutex);
[984a9ba]1160 async_answer_0(&call, rc);
1161 async_answer_0(icall, rc);
[cc574511]1162 return;
1163 }
[a35b458]1164
[cc574511]1165 fibril_mutex_unlock(&cat->mutex);
1166 fibril_mutex_unlock(&cdir.mutex);
[a35b458]1167
[984a9ba]1168 errno_t retval = async_data_read_finalize(&call, id_buf, size);
[cc574511]1169 free(id_buf);
[a35b458]1170
[984a9ba]1171 async_answer_1(icall, retval, act_size);
[cc574511]1172}
1173
1174
[984a9ba]1175static void loc_null_create(ipc_call_t *icall)
[15f3c3f]1176{
1177 fibril_mutex_lock(&null_services_mutex);
[a35b458]1178
[15f3c3f]1179 unsigned int i;
1180 bool fnd = false;
[a35b458]1181
[15f3c3f]1182 for (i = 0; i < NULL_SERVICES; i++) {
1183 if (null_services[i] == NULL) {
1184 fnd = true;
1185 break;
1186 }
1187 }
[a35b458]1188
[15f3c3f]1189 if (!fnd) {
1190 fibril_mutex_unlock(&null_services_mutex);
[984a9ba]1191 async_answer_0(icall, ENOMEM);
[15f3c3f]1192 return;
1193 }
[a35b458]1194
[15f3c3f]1195 char null[LOC_NAME_MAXLEN];
1196 snprintf(null, LOC_NAME_MAXLEN, "%u", i);
[a35b458]1197
[15f3c3f]1198 char *dev_name = str_dup(null);
1199 if (dev_name == NULL) {
1200 fibril_mutex_unlock(&null_services_mutex);
[984a9ba]1201 async_answer_0(icall, ENOMEM);
[15f3c3f]1202 return;
1203 }
[a35b458]1204
[15f3c3f]1205 loc_service_t *service =
1206 (loc_service_t *) malloc(sizeof(loc_service_t));
1207 if (service == NULL) {
1208 fibril_mutex_unlock(&null_services_mutex);
[984a9ba]1209 async_answer_0(icall, ENOMEM);
[15f3c3f]1210 return;
1211 }
[a35b458]1212
[15f3c3f]1213 fibril_mutex_lock(&services_list_mutex);
[a35b458]1214
[15f3c3f]1215 loc_namespace_t *namespace = loc_namespace_create("null");
1216 if (namespace == NULL) {
1217 fibril_mutex_lock(&services_list_mutex);
1218 fibril_mutex_unlock(&null_services_mutex);
[984a9ba]1219 async_answer_0(icall, ENOMEM);
[15f3c3f]1220 return;
1221 }
[a35b458]1222
[15f3c3f]1223 link_initialize(&service->services);
1224 link_initialize(&service->server_services);
[03f4acf]1225 list_initialize(&service->cat_memb);
[a35b458]1226
[15f3c3f]1227 /* Get unique service ID */
1228 service->id = loc_create_id();
1229 service->server = NULL;
[a35b458]1230
[15f3c3f]1231 loc_namespace_addref(namespace, service);
1232 service->name = dev_name;
[a35b458]1233
[15f3c3f]1234 /*
1235 * Insert service into list of all services and into null services array.
1236 * Insert service into a dummy list of null server's services so that it
1237 * can be safely removed later.
1238 */
1239 list_append(&service->services, &services_list);
1240 list_append(&service->server_services, &dummy_null_services);
1241 null_services[i] = service;
[a35b458]1242
[15f3c3f]1243 fibril_mutex_unlock(&services_list_mutex);
1244 fibril_mutex_unlock(&null_services_mutex);
[a35b458]1245
[984a9ba]1246 async_answer_1(icall, EOK, (sysarg_t) i);
[15f3c3f]1247}
1248
[984a9ba]1249static void loc_null_destroy(ipc_call_t *icall)
[15f3c3f]1250{
1251 sysarg_t i = IPC_GET_ARG1(*icall);
1252 if (i >= NULL_SERVICES) {
[984a9ba]1253 async_answer_0(icall, ELIMIT);
[15f3c3f]1254 return;
1255 }
[a35b458]1256
[15f3c3f]1257 fibril_mutex_lock(&null_services_mutex);
[a35b458]1258
[15f3c3f]1259 if (null_services[i] == NULL) {
1260 fibril_mutex_unlock(&null_services_mutex);
[984a9ba]1261 async_answer_0(icall, ENOENT);
[15f3c3f]1262 return;
1263 }
[a35b458]1264
[15f3c3f]1265 fibril_mutex_lock(&services_list_mutex);
[d0dd7b5]1266 fibril_mutex_lock(&cdir.mutex);
[15f3c3f]1267 loc_service_unregister_core(null_services[i]);
[d0dd7b5]1268 fibril_mutex_unlock(&cdir.mutex);
[15f3c3f]1269 fibril_mutex_unlock(&services_list_mutex);
[a35b458]1270
[15f3c3f]1271 null_services[i] = NULL;
[a35b458]1272
[15f3c3f]1273 fibril_mutex_unlock(&null_services_mutex);
[984a9ba]1274 async_answer_0(icall, EOK);
[15f3c3f]1275}
1276
[984a9ba]1277static void loc_service_add_to_cat(ipc_call_t *icall)
[cc574511]1278{
1279 category_t *cat;
1280 loc_service_t *svc;
1281 catid_t cat_id;
1282 service_id_t svc_id;
[5a6cc679]1283 errno_t retval;
[a35b458]1284
[cc574511]1285 svc_id = IPC_GET_ARG1(*icall);
1286 cat_id = IPC_GET_ARG2(*icall);
[a35b458]1287
[cc574511]1288 fibril_mutex_lock(&services_list_mutex);
1289 fibril_mutex_lock(&cdir.mutex);
[a35b458]1290
[cc574511]1291 cat = category_get(&cdir, cat_id);
1292 svc = loc_service_find_id(svc_id);
[a35b458]1293
[aff587f]1294 if (cat == NULL || svc == NULL) {
1295 fibril_mutex_unlock(&cdir.mutex);
1296 fibril_mutex_unlock(&services_list_mutex);
[984a9ba]1297 async_answer_0(icall, ENOENT);
[aff587f]1298 return;
1299 }
[a35b458]1300
[cc574511]1301 fibril_mutex_lock(&cat->mutex);
1302 retval = category_add_service(cat, svc);
1303
1304 fibril_mutex_unlock(&cat->mutex);
1305 fibril_mutex_unlock(&cdir.mutex);
1306 fibril_mutex_unlock(&services_list_mutex);
1307
[adb1ae9]1308 /*
1309 * First send out all notifications and only then answer the request.
1310 * Otherwise the current fibril might block and transitively wait for
1311 * the completion of requests that are routed to it via an IPC loop.
1312 */
[12f9f0d0]1313 loc_category_change_event();
[984a9ba]1314 async_answer_0(icall, retval);
[cc574511]1315}
1316
1317
[15f3c3f]1318/** Initialize location service.
1319 *
1320 *
1321 */
1322static bool loc_init(void)
1323{
1324 unsigned int i;
[cc574511]1325 category_t *cat;
1326
[15f3c3f]1327 for (i = 0; i < NULL_SERVICES; i++)
1328 null_services[i] = NULL;
[a35b458]1329
[cc574511]1330 categ_dir_init(&cdir);
1331
[e96047c]1332 cat = category_new("disk");
1333 categ_dir_add_cat(&cdir, cat);
1334
[372df8f]1335 cat = category_new("partition");
1336 categ_dir_add_cat(&cdir, cat);
1337
[e2e56e67]1338 cat = category_new("iplink");
1339 categ_dir_add_cat(&cdir, cat);
1340
[cc574511]1341 cat = category_new("keyboard");
1342 categ_dir_add_cat(&cdir, cat);
1343
1344 cat = category_new("mouse");
1345 categ_dir_add_cat(&cdir, cat);
1346
[1e94e09]1347 cat = category_new("led");
1348 categ_dir_add_cat(&cdir, cat);
1349
[cc574511]1350 cat = category_new("serial");
1351 categ_dir_add_cat(&cdir, cat);
1352
[9940ce0]1353 cat = category_new("console");
1354 categ_dir_add_cat(&cdir, cat);
1355
[557b7b3]1356 cat = category_new("clock");
1357 categ_dir_add_cat(&cdir, cat);
1358
[a9abe5fc]1359 cat = category_new("test3");
1360 categ_dir_add_cat(&cdir, cat);
1361
[64d138b]1362 cat = category_new("usbdiag");
1363 categ_dir_add_cat(&cdir, cat);
1364
[e280857]1365 cat = category_new("usbhc");
1366 categ_dir_add_cat(&cdir, cat);
1367
[a9abe5fc]1368 cat = category_new("virt-null");
1369 categ_dir_add_cat(&cdir, cat);
1370
[d0dd7b5]1371 cat = category_new("virtual");
1372 categ_dir_add_cat(&cdir, cat);
[a35b458]1373
[609243f4]1374 cat = category_new("nic");
1375 categ_dir_add_cat(&cdir, cat);
[a35b458]1376
[864762a]1377 cat = category_new("ieee80211");
1378 categ_dir_add_cat(&cdir, cat);
[6d5e378]1379
[9a2eb14]1380 cat = category_new("irc");
1381 categ_dir_add_cat(&cdir, cat);
1382
[6d5e378]1383 cat = category_new("visualizer");
1384 categ_dir_add_cat(&cdir, cat);
1385
1386 cat = category_new("renderer");
1387 categ_dir_add_cat(&cdir, cat);
[a35b458]1388
[94694a4]1389 cat = category_new("audio-pcm");
1390 categ_dir_add_cat(&cdir, cat);
[a35b458]1391
[15f3c3f]1392 return true;
1393}
1394
1395/** Handle connection on supplier port.
1396 *
1397 */
[984a9ba]1398static void loc_connection_supplier(ipc_call_t *icall, void *arg)
[15f3c3f]1399{
1400 /* Accept connection */
[984a9ba]1401 async_answer_0(icall, EOK);
[a35b458]1402
[15f3c3f]1403 loc_server_t *server = loc_server_register();
1404 if (server == NULL)
1405 return;
[a35b458]1406
[15f3c3f]1407 while (true) {
1408 ipc_call_t call;
[984a9ba]1409 async_get_call(&call);
[a35b458]1410
[15f3c3f]1411 if (!IPC_GET_IMETHOD(call))
1412 break;
[a35b458]1413
[15f3c3f]1414 switch (IPC_GET_IMETHOD(call)) {
1415 case LOC_SERVER_UNREGISTER:
1416 if (server == NULL)
[984a9ba]1417 async_answer_0(&call, ENOENT);
[15f3c3f]1418 else
[984a9ba]1419 async_answer_0(&call, EOK);
[15f3c3f]1420 break;
[cc574511]1421 case LOC_SERVICE_ADD_TO_CAT:
1422 /* Add service to category */
[984a9ba]1423 loc_service_add_to_cat(&call);
[cc574511]1424 break;
[15f3c3f]1425 case LOC_SERVICE_REGISTER:
1426 /* Register one service */
[984a9ba]1427 loc_service_register(&call, server);
[15f3c3f]1428 break;
1429 case LOC_SERVICE_UNREGISTER:
1430 /* Remove one service */
[984a9ba]1431 loc_service_unregister(&call, server);
[15f3c3f]1432 break;
1433 case LOC_SERVICE_GET_ID:
[984a9ba]1434 loc_service_get_id(&call);
[15f3c3f]1435 break;
1436 case LOC_NAMESPACE_GET_ID:
[984a9ba]1437 loc_namespace_get_id(&call);
[15f3c3f]1438 break;
1439 default:
[984a9ba]1440 async_answer_0(&call, ENOENT);
[15f3c3f]1441 }
1442 }
[a35b458]1443
[15f3c3f]1444 if (server != NULL) {
1445 /*
1446 * Unregister the server and all its services.
1447 */
1448 loc_server_unregister(server);
1449 server = NULL;
1450 }
1451}
1452
1453/** Handle connection on consumer port.
1454 *
1455 */
[984a9ba]1456static void loc_connection_consumer(ipc_call_t *icall, void *arg)
[15f3c3f]1457{
1458 /* Accept connection */
[984a9ba]1459 async_answer_0(icall, EOK);
[a35b458]1460
[15f3c3f]1461 while (true) {
1462 ipc_call_t call;
[984a9ba]1463 async_get_call(&call);
[a35b458]1464
[15f3c3f]1465 if (!IPC_GET_IMETHOD(call))
1466 break;
[a35b458]1467
[15f3c3f]1468 switch (IPC_GET_IMETHOD(call)) {
1469 case LOC_SERVICE_GET_ID:
[984a9ba]1470 loc_service_get_id(&call);
[15f3c3f]1471 break;
[cce8a83]1472 case LOC_SERVICE_GET_NAME:
[984a9ba]1473 loc_service_get_name(&call);
[cce8a83]1474 break;
[a3fcfba]1475 case LOC_SERVICE_GET_SERVER_NAME:
[984a9ba]1476 loc_service_get_server_name(&call);
[a3fcfba]1477 break;
[15f3c3f]1478 case LOC_NAMESPACE_GET_ID:
[984a9ba]1479 loc_namespace_get_id(&call);
[15f3c3f]1480 break;
[12f9f0d0]1481 case LOC_CALLBACK_CREATE:
[984a9ba]1482 loc_callback_create(&call);
[12f9f0d0]1483 break;
[cc574511]1484 case LOC_CATEGORY_GET_ID:
[984a9ba]1485 loc_category_get_id(&call);
[cc574511]1486 break;
[763e0cd]1487 case LOC_CATEGORY_GET_NAME:
[984a9ba]1488 loc_category_get_name(&call);
[763e0cd]1489 break;
[cc574511]1490 case LOC_CATEGORY_GET_SVCS:
[984a9ba]1491 loc_category_get_svcs(&call);
[cc574511]1492 break;
[15f3c3f]1493 case LOC_ID_PROBE:
[984a9ba]1494 loc_id_probe(&call);
[15f3c3f]1495 break;
1496 case LOC_NULL_CREATE:
[984a9ba]1497 loc_null_create(&call);
[15f3c3f]1498 break;
1499 case LOC_NULL_DESTROY:
[984a9ba]1500 loc_null_destroy(&call);
[15f3c3f]1501 break;
1502 case LOC_GET_NAMESPACE_COUNT:
[984a9ba]1503 loc_get_namespace_count(&call);
[15f3c3f]1504 break;
1505 case LOC_GET_SERVICE_COUNT:
[984a9ba]1506 loc_get_service_count(&call);
[15f3c3f]1507 break;
[278ac72]1508 case LOC_GET_CATEGORIES:
[984a9ba]1509 loc_get_categories(&call);
[278ac72]1510 break;
[15f3c3f]1511 case LOC_GET_NAMESPACES:
[984a9ba]1512 loc_get_namespaces(&call);
[15f3c3f]1513 break;
1514 case LOC_GET_SERVICES:
[984a9ba]1515 loc_get_services(&call);
[15f3c3f]1516 break;
1517 default:
[984a9ba]1518 async_answer_0(&call, ENOENT);
[15f3c3f]1519 }
1520 }
1521}
1522
1523/**
1524 *
1525 */
1526int main(int argc, char *argv[])
1527{
1528 printf("%s: HelenOS Location Service\n", NAME);
[a35b458]1529
[15f3c3f]1530 if (!loc_init()) {
1531 printf("%s: Error while initializing service\n", NAME);
1532 return -1;
1533 }
[a35b458]1534
[9b1baac]1535 /* Register location service at naming service */
1536 errno_t rc = service_register(SERVICE_LOC, INTERFACE_LOC_SUPPLIER,
1537 loc_connection_supplier, NULL);
[c1694b6b]1538 if (rc != EOK) {
[9b1baac]1539 printf("%s: Error while registering supplier service: %s\n", NAME, str_error(rc));
[f9b2cb4c]1540 return rc;
[c1694b6b]1541 }
[a35b458]1542
[9b1baac]1543 rc = service_register(SERVICE_LOC, INTERFACE_LOC_CONSUMER,
1544 loc_connection_consumer, NULL);
[c1694b6b]1545 if (rc != EOK) {
[9b1baac]1546 printf("%s: Error while registering consumer service: %s\n", NAME, str_error(rc));
[f9b2cb4c]1547 return rc;
[c1694b6b]1548 }
[a35b458]1549
[9b1baac]1550 rc = service_register_broker(SERVICE_LOC, loc_forward, NULL);
[c1694b6b]1551 if (rc != EOK) {
[9b1baac]1552 printf("%s: Error while registering broker service: %s\n", NAME, str_error(rc));
[50ad3f3]1553 return rc;
[c1694b6b]1554 }
[a35b458]1555
[15f3c3f]1556 printf("%s: Accepting connections\n", NAME);
1557 async_manager();
[a35b458]1558
[15f3c3f]1559 /* Never reached */
1560 return 0;
1561}
1562
1563/**
1564 * @}
1565 */
Note: See TracBrowser for help on using the repository browser.