source: mainline/uspace/srv/locsrv/locsrv.c@ 901b302

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 901b302 was 54593f3, checked in by Jiri Svoboda <jiri@…>, 3 years ago

Remove obsolete 'renderer' category

  • Property mode set to 100644
File size: 35.0 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;
[28a5ebd]127 char32_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
[fafb8e5]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);
[fafb8e5]549 svc = loc_service_find_id(ipc_get_arg1(icall));
[d0dd7b5]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
[fafb8e5]585 cat = category_get(&cdir, ipc_get_arg1(icall));
[763e0cd]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
[fafb8e5]625 svc = loc_service_find_id(ipc_get_arg1(icall));
[cce8a83]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
[fafb8e5]673 svc = loc_service_find_id(ipc_get_arg1(icall));
[a3fcfba]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 */
[fafb8e5]717 iface_t iface = ipc_get_arg1(call);
718 service_id_t id = ipc_get_arg2(call);
[15f3c3f]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);
[4f13e19]728 async_forward_1(call, exch, iface, svc->id, 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) {
[fafb8e5]776 if (ipc_get_arg1(icall) & IPC_FLAG_BLOCKING) {
[15f3c3f]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) {
[fafb8e5]829 if (ipc_get_arg1(icall) & IPC_FLAG_BLOCKING) {
[15f3c3f]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 =
[fafb8e5]934 loc_namespace_find_id(ipc_get_arg1(icall));
[15f3c3f]935 if (namespace == NULL) {
936 loc_service_t *svc =
[fafb8e5]937 loc_service_find_id(ipc_get_arg1(icall));
[15f3c3f]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 =
[fafb8e5]960 loc_namespace_find_id(ipc_get_arg1(icall));
[15f3c3f]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 =
[fafb8e5]1081 loc_namespace_find_id(ipc_get_arg1(icall));
[15f3c3f]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
[fafb8e5]1137 category_t *cat = category_get(&cdir, ipc_get_arg1(icall));
[cc574511]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{
[fafb8e5]1249 sysarg_t i = ipc_get_arg1(icall);
[15f3c3f]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
[fafb8e5]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
[87a7cdb]1380 cat = category_new("display-device");
[6d5e378]1381 categ_dir_add_cat(&cdir, cat);
[a35b458]1382
[94694a4]1383 cat = category_new("audio-pcm");
1384 categ_dir_add_cat(&cdir, cat);
[a35b458]1385
[10b21a1b]1386 cat = category_new("printer-port");
1387 categ_dir_add_cat(&cdir, cat);
1388
[7acd787]1389 cat = category_new("pci");
1390 categ_dir_add_cat(&cdir, cat);
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 */
[beb83c1]1401 async_accept_0(icall);
[a35b458]1402
[ee9c703]1403 /*
1404 * Each connection begins by a LOC_SERVER_REGISTER, which precludes us
1405 * from using parallel exchanges.
1406 */
1407 static_assert((INTERFACE_LOC_SUPPLIER & IFACE_EXCHANGE_MASK) ==
[0a520db]1408 IFACE_EXCHANGE_SERIALIZE, "");
[ee9c703]1409
[15f3c3f]1410 loc_server_t *server = loc_server_register();
1411 if (server == NULL)
1412 return;
[a35b458]1413
[15f3c3f]1414 while (true) {
1415 ipc_call_t call;
[984a9ba]1416 async_get_call(&call);
[a35b458]1417
[fafb8e5]1418 if (!ipc_get_imethod(&call)) {
[889cdb1]1419 async_answer_0(&call, EOK);
[15f3c3f]1420 break;
[889cdb1]1421 }
[a35b458]1422
[fafb8e5]1423 switch (ipc_get_imethod(&call)) {
[15f3c3f]1424 case LOC_SERVER_UNREGISTER:
1425 if (server == NULL)
[984a9ba]1426 async_answer_0(&call, ENOENT);
[15f3c3f]1427 else
[984a9ba]1428 async_answer_0(&call, EOK);
[15f3c3f]1429 break;
[cc574511]1430 case LOC_SERVICE_ADD_TO_CAT:
1431 /* Add service to category */
[984a9ba]1432 loc_service_add_to_cat(&call);
[cc574511]1433 break;
[15f3c3f]1434 case LOC_SERVICE_REGISTER:
1435 /* Register one service */
[984a9ba]1436 loc_service_register(&call, server);
[15f3c3f]1437 break;
1438 case LOC_SERVICE_UNREGISTER:
1439 /* Remove one service */
[984a9ba]1440 loc_service_unregister(&call, server);
[15f3c3f]1441 break;
1442 case LOC_SERVICE_GET_ID:
[984a9ba]1443 loc_service_get_id(&call);
[15f3c3f]1444 break;
1445 case LOC_NAMESPACE_GET_ID:
[984a9ba]1446 loc_namespace_get_id(&call);
[15f3c3f]1447 break;
1448 default:
[984a9ba]1449 async_answer_0(&call, ENOENT);
[15f3c3f]1450 }
1451 }
[a35b458]1452
[15f3c3f]1453 if (server != NULL) {
1454 /*
1455 * Unregister the server and all its services.
1456 */
1457 loc_server_unregister(server);
1458 server = NULL;
1459 }
1460}
1461
1462/** Handle connection on consumer port.
1463 *
1464 */
[984a9ba]1465static void loc_connection_consumer(ipc_call_t *icall, void *arg)
[15f3c3f]1466{
1467 /* Accept connection */
[beb83c1]1468 async_accept_0(icall);
[a35b458]1469
[15f3c3f]1470 while (true) {
1471 ipc_call_t call;
[984a9ba]1472 async_get_call(&call);
[a35b458]1473
[fafb8e5]1474 if (!ipc_get_imethod(&call)) {
[889cdb1]1475 async_answer_0(&call, EOK);
[15f3c3f]1476 break;
[889cdb1]1477 }
[a35b458]1478
[fafb8e5]1479 switch (ipc_get_imethod(&call)) {
[15f3c3f]1480 case LOC_SERVICE_GET_ID:
[984a9ba]1481 loc_service_get_id(&call);
[15f3c3f]1482 break;
[cce8a83]1483 case LOC_SERVICE_GET_NAME:
[984a9ba]1484 loc_service_get_name(&call);
[cce8a83]1485 break;
[a3fcfba]1486 case LOC_SERVICE_GET_SERVER_NAME:
[984a9ba]1487 loc_service_get_server_name(&call);
[a3fcfba]1488 break;
[15f3c3f]1489 case LOC_NAMESPACE_GET_ID:
[984a9ba]1490 loc_namespace_get_id(&call);
[15f3c3f]1491 break;
[12f9f0d0]1492 case LOC_CALLBACK_CREATE:
[984a9ba]1493 loc_callback_create(&call);
[12f9f0d0]1494 break;
[cc574511]1495 case LOC_CATEGORY_GET_ID:
[984a9ba]1496 loc_category_get_id(&call);
[cc574511]1497 break;
[763e0cd]1498 case LOC_CATEGORY_GET_NAME:
[984a9ba]1499 loc_category_get_name(&call);
[763e0cd]1500 break;
[cc574511]1501 case LOC_CATEGORY_GET_SVCS:
[984a9ba]1502 loc_category_get_svcs(&call);
[cc574511]1503 break;
[15f3c3f]1504 case LOC_ID_PROBE:
[984a9ba]1505 loc_id_probe(&call);
[15f3c3f]1506 break;
1507 case LOC_NULL_CREATE:
[984a9ba]1508 loc_null_create(&call);
[15f3c3f]1509 break;
1510 case LOC_NULL_DESTROY:
[984a9ba]1511 loc_null_destroy(&call);
[15f3c3f]1512 break;
1513 case LOC_GET_NAMESPACE_COUNT:
[984a9ba]1514 loc_get_namespace_count(&call);
[15f3c3f]1515 break;
1516 case LOC_GET_SERVICE_COUNT:
[984a9ba]1517 loc_get_service_count(&call);
[15f3c3f]1518 break;
[278ac72]1519 case LOC_GET_CATEGORIES:
[984a9ba]1520 loc_get_categories(&call);
[278ac72]1521 break;
[15f3c3f]1522 case LOC_GET_NAMESPACES:
[984a9ba]1523 loc_get_namespaces(&call);
[15f3c3f]1524 break;
1525 case LOC_GET_SERVICES:
[984a9ba]1526 loc_get_services(&call);
[15f3c3f]1527 break;
1528 default:
[984a9ba]1529 async_answer_0(&call, ENOENT);
[15f3c3f]1530 }
1531 }
1532}
1533
1534/**
1535 *
1536 */
1537int main(int argc, char *argv[])
1538{
1539 printf("%s: HelenOS Location Service\n", NAME);
[a35b458]1540
[15f3c3f]1541 if (!loc_init()) {
1542 printf("%s: Error while initializing service\n", NAME);
1543 return -1;
1544 }
[a35b458]1545
[9b1baac]1546 /* Register location service at naming service */
1547 errno_t rc = service_register(SERVICE_LOC, INTERFACE_LOC_SUPPLIER,
1548 loc_connection_supplier, NULL);
[c1694b6b]1549 if (rc != EOK) {
[9b1baac]1550 printf("%s: Error while registering supplier service: %s\n", NAME, str_error(rc));
[f9b2cb4c]1551 return rc;
[c1694b6b]1552 }
[a35b458]1553
[9b1baac]1554 rc = service_register(SERVICE_LOC, INTERFACE_LOC_CONSUMER,
1555 loc_connection_consumer, NULL);
[c1694b6b]1556 if (rc != EOK) {
[9b1baac]1557 printf("%s: Error while registering consumer service: %s\n", NAME, str_error(rc));
[f9b2cb4c]1558 return rc;
[c1694b6b]1559 }
[a35b458]1560
[9b1baac]1561 rc = service_register_broker(SERVICE_LOC, loc_forward, NULL);
[c1694b6b]1562 if (rc != EOK) {
[9b1baac]1563 printf("%s: Error while registering broker service: %s\n", NAME, str_error(rc));
[50ad3f3]1564 return rc;
[c1694b6b]1565 }
[a35b458]1566
[15f3c3f]1567 printf("%s: Accepting connections\n", NAME);
1568 async_manager();
[a35b458]1569
[15f3c3f]1570 /* Never reached */
1571 return 0;
1572}
1573
1574/**
1575 * @}
1576 */
Note: See TracBrowser for help on using the repository browser.