source: mainline/uspace/srv/locsrv/locsrv.c@ 5c38838

Last change on this file since 5c38838 was ee9c703, checked in by Jakub Jermar <jakub@…>, 7 years ago

Make INTERFACE_LOC_SUPPLIER serial again

This commit entirely reverts commit cbdb38ff8f. The interface
unfortunately cannot be parallel/cloned due to the fact that each loc
supplier connection is stateful and is expected to begin with a
LOC_SERVER_REGISTER call. Failing that, cloned exchanges to the
location service supplier interface immediately fail with EREFUSED,
because the method mismatches.

This results in various sporadic failures to register services or add
services into categories, which in turn results in symptoms such as
non-functioning keyboard and mouse input.

If memory serves well, the issue that cbdb38ff8f addressed was that
category change events can transitively result in new requests to the
interface over the same phone. Around the time of cbdb38ff8f there used
to be a hard limit on the number of concurrent async calls and calls
that exceeded this limit got blocked. This is no longer the case, so the
loc supplier fibril is not waiting for any of its own IPC. Hence
reverting cbdb38ff8f should be safe.

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