source: mainline/uspace/srv/locsrv/locsrv.c@ 742fc98e

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

Make ccheck-fix again and commit more good files.

  • Property mode set to 100644
File size: 36.5 KB
RevLine 
[15f3c3f]1/*
2 * Copyright (c) 2007 Josef Cejka
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/**
31 * @defgroup loc Location Service.
32 * @brief HelenOS location service.
33 * @{
34 */
35
36/** @file
37 */
38
39#include <ipc/services.h>
40#include <ns.h>
41#include <async.h>
42#include <stdio.h>
43#include <errno.h>
[3e6a98c5]44#include <stdbool.h>
[15f3c3f]45#include <fibril_synch.h>
[cce8a83]46#include <macros.h>
[15f3c3f]47#include <stdlib.h>
48#include <str.h>
[c1694b6b]49#include <str_error.h>
[15f3c3f]50#include <ipc/loc.h>
51#include <assert.h>
52
[cc574511]53#include "category.h"
[32d96e1]54#include "locsrv.h"
[cc574511]55
[15f3c3f]56#define NAME "loc"
57#define NULL_SERVICES 256
58
[77a69ea]59/** Callback session */
60typedef struct {
61 link_t cb_sess_list;
62 async_sess_t *sess;
63} cb_sess_t;
64
[15f3c3f]65LIST_INITIALIZE(services_list);
66LIST_INITIALIZE(namespaces_list);
67LIST_INITIALIZE(servers_list);
68
69/* Locking order:
70 * servers_list_mutex
71 * services_list_mutex
72 * (loc_server_t *)->services_mutex
73 * create_id_mutex
74 **/
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{
99 /* TODO: allow reusing old ids after their unregistration
100 * and implement some version of LRU algorithm, avoid overflow
101 */
[a35b458]102
[15f3c3f]103 fibril_mutex_lock(&create_id_mutex);
104 last_id++;
105 fibril_mutex_unlock(&create_id_mutex);
[a35b458]106
[15f3c3f]107 return last_id;
108}
109
110/** Convert fully qualified service name to namespace and service name.
111 *
112 * A fully qualified service name can be either a plain service name
113 * (then the namespace is considered to be an empty string) or consist
114 * of two components separated by a slash. No more than one slash
115 * is allowed.
116 *
117 */
118static bool loc_fqsn_split(const char *fqsn, char **ns_name, char **name)
119{
120 size_t cnt = 0;
121 size_t slash_offset = 0;
122 size_t slash_after = 0;
[a35b458]123
[15f3c3f]124 size_t offset = 0;
125 size_t offset_prev = 0;
126 wchar_t c;
[a35b458]127
[15f3c3f]128 while ((c = str_decode(fqsn, &offset, STR_NO_LIMIT)) != 0) {
129 if (c == '/') {
130 cnt++;
131 slash_offset = offset_prev;
132 slash_after = offset;
133 }
134 offset_prev = offset;
135 }
[a35b458]136
[15f3c3f]137 /* More than one slash */
138 if (cnt > 1)
139 return false;
[a35b458]140
[15f3c3f]141 /* No slash -> namespace is empty */
142 if (cnt == 0) {
143 *ns_name = str_dup("");
144 if (*ns_name == NULL)
145 return false;
[a35b458]146
[15f3c3f]147 *name = str_dup(fqsn);
148 if (*name == NULL) {
149 free(*ns_name);
150 return false;
151 }
[a35b458]152
[15f3c3f]153 if (str_cmp(*name, "") == 0) {
154 free(*name);
155 free(*ns_name);
156 return false;
157 }
[a35b458]158
[15f3c3f]159 return true;
160 }
[a35b458]161
[15f3c3f]162 /* Exactly one slash */
163 *ns_name = str_ndup(fqsn, slash_offset);
164 if (*ns_name == NULL)
165 return false;
[a35b458]166
[15f3c3f]167 *name = str_dup(fqsn + slash_after);
168 if (*name == NULL) {
169 free(*ns_name);
170 return false;
171 }
[a35b458]172
[15f3c3f]173 if (str_cmp(*name, "") == 0) {
174 free(*name);
175 free(*ns_name);
176 return false;
177 }
[a35b458]178
[15f3c3f]179 return true;
180}
181
182/** Find namespace with given name. */
183static loc_namespace_t *loc_namespace_find_name(const char *name)
184{
185 assert(fibril_mutex_is_locked(&services_list_mutex));
[a35b458]186
[feeac0d]187 list_foreach(namespaces_list, namespaces, loc_namespace_t, namespace) {
[15f3c3f]188 if (str_cmp(namespace->name, name) == 0)
189 return namespace;
190 }
[a35b458]191
[15f3c3f]192 return NULL;
193}
194
195/** Find namespace with given ID.
196 *
197 * @todo: use hash table
198 *
199 */
200static loc_namespace_t *loc_namespace_find_id(service_id_t id)
201{
202 assert(fibril_mutex_is_locked(&services_list_mutex));
[a35b458]203
[feeac0d]204 list_foreach(namespaces_list, namespaces, loc_namespace_t, namespace) {
[15f3c3f]205 if (namespace->id == id)
206 return namespace;
207 }
[a35b458]208
[15f3c3f]209 return NULL;
210}
211
212/** Find service with given name. */
213static loc_service_t *loc_service_find_name(const char *ns_name,
214 const char *name)
215{
216 assert(fibril_mutex_is_locked(&services_list_mutex));
[a35b458]217
[feeac0d]218 list_foreach(services_list, services, loc_service_t, service) {
[3bacee1]219 if ((str_cmp(service->namespace->name, ns_name) == 0) &&
220 (str_cmp(service->name, name) == 0))
[15f3c3f]221 return service;
222 }
[a35b458]223
[15f3c3f]224 return NULL;
225}
226
227/** Find service with given ID.
228 *
229 * @todo: use hash table
230 *
231 */
232static loc_service_t *loc_service_find_id(service_id_t id)
233{
234 assert(fibril_mutex_is_locked(&services_list_mutex));
[a35b458]235
[feeac0d]236 list_foreach(services_list, services, loc_service_t, service) {
[15f3c3f]237 if (service->id == id)
238 return service;
239 }
[a35b458]240
[15f3c3f]241 return NULL;
242}
243
244/** Create a namespace (if not already present). */
245static loc_namespace_t *loc_namespace_create(const char *ns_name)
246{
247 loc_namespace_t *namespace;
[a35b458]248
[15f3c3f]249 assert(fibril_mutex_is_locked(&services_list_mutex));
[a35b458]250
[15f3c3f]251 namespace = loc_namespace_find_name(ns_name);
252 if (namespace != NULL)
253 return namespace;
[a35b458]254
[15f3c3f]255 namespace = (loc_namespace_t *) malloc(sizeof(loc_namespace_t));
256 if (namespace == NULL)
257 return NULL;
[a35b458]258
[15f3c3f]259 namespace->name = str_dup(ns_name);
260 if (namespace->name == NULL) {
261 free(namespace);
262 return NULL;
263 }
[a35b458]264
[15f3c3f]265 namespace->id = loc_create_id();
266 namespace->refcnt = 0;
[a35b458]267
[15f3c3f]268 /*
269 * Insert new namespace into list of registered namespaces
270 */
271 list_append(&(namespace->namespaces), &namespaces_list);
[a35b458]272
[15f3c3f]273 return namespace;
274}
275
276/** Destroy a namespace (if it is no longer needed). */
277static void loc_namespace_destroy(loc_namespace_t *namespace)
278{
279 assert(fibril_mutex_is_locked(&services_list_mutex));
280
281 if (namespace->refcnt == 0) {
282 list_remove(&(namespace->namespaces));
[a35b458]283
[15f3c3f]284 free(namespace->name);
285 free(namespace);
286 }
287}
288
289/** Increase namespace reference count by including service. */
290static void loc_namespace_addref(loc_namespace_t *namespace,
291 loc_service_t *service)
292{
293 assert(fibril_mutex_is_locked(&services_list_mutex));
294
295 service->namespace = namespace;
296 namespace->refcnt++;
297}
298
299/** Decrease namespace reference count. */
300static void loc_namespace_delref(loc_namespace_t *namespace)
301{
302 assert(fibril_mutex_is_locked(&services_list_mutex));
303
304 namespace->refcnt--;
305 loc_namespace_destroy(namespace);
306}
307
308/** Unregister service and free it. */
309static void loc_service_unregister_core(loc_service_t *service)
310{
311 assert(fibril_mutex_is_locked(&services_list_mutex));
[d0dd7b5]312 assert(fibril_mutex_is_locked(&cdir.mutex));
[a35b458]313
[15f3c3f]314 loc_namespace_delref(service->namespace);
315 list_remove(&(service->services));
316 list_remove(&(service->server_services));
[a35b458]317
[d0dd7b5]318 /* Remove service from all categories. */
319 while (!list_empty(&service->cat_memb)) {
320 link_t *link = list_first(&service->cat_memb);
321 svc_categ_t *memb = list_get_instance(link, svc_categ_t,
322 svc_link);
[69d25e2]323 category_t *cat = memb->cat;
[a35b458]324
[69d25e2]325 fibril_mutex_lock(&cat->mutex);
[d0dd7b5]326 category_remove_service(memb);
[69d25e2]327 fibril_mutex_unlock(&cat->mutex);
[d0dd7b5]328 }
[a35b458]329
[15f3c3f]330 free(service->name);
331 free(service);
332}
333
334/**
335 * Read info about new server and add it into linked list of registered
336 * servers.
337 */
338static loc_server_t *loc_server_register(void)
339{
340 ipc_call_t icall;
[a46e56b]341 cap_call_handle_t icall_handle = async_get_call(&icall);
[a35b458]342
[15f3c3f]343 if (IPC_GET_IMETHOD(icall) != LOC_SERVER_REGISTER) {
[a46e56b]344 async_answer_0(icall_handle, EREFUSED);
[15f3c3f]345 return NULL;
346 }
[a35b458]347
[15f3c3f]348 loc_server_t *server =
349 (loc_server_t *) malloc(sizeof(loc_server_t));
350 if (server == NULL) {
[a46e56b]351 async_answer_0(icall_handle, ENOMEM);
[15f3c3f]352 return NULL;
353 }
[a35b458]354
[15f3c3f]355 /*
356 * Get server name
357 */
[5a6cc679]358 errno_t rc = async_data_write_accept((void **) &server->name, true, 0,
[15f3c3f]359 LOC_NAME_MAXLEN, 0, NULL);
360 if (rc != EOK) {
361 free(server);
[a46e56b]362 async_answer_0(icall_handle, rc);
[15f3c3f]363 return NULL;
364 }
[a35b458]365
[15f3c3f]366 /*
367 * Create connection to the server
368 */
369 server->sess = async_callback_receive(EXCHANGE_SERIALIZE);
370 if (!server->sess) {
371 free(server->name);
372 free(server);
[a46e56b]373 async_answer_0(icall_handle, ENOTSUP);
[15f3c3f]374 return NULL;
375 }
[a35b458]376
[15f3c3f]377 /*
378 * Initialize mutex for list of services
379 * supplied by this server
380 */
381 fibril_mutex_initialize(&server->services_mutex);
[a35b458]382
[15f3c3f]383 /*
384 * Initialize list of supplied services
385 */
386 list_initialize(&server->services);
387 link_initialize(&server->servers);
[a35b458]388
[15f3c3f]389 fibril_mutex_lock(&servers_list_mutex);
[a35b458]390
[15f3c3f]391 /* TODO:
392 * Check that no server with name equal to
393 * server->name is registered
394 */
[a35b458]395
[15f3c3f]396 /*
397 * Insert new server into list of registered servers
398 */
399 list_append(&(server->servers), &servers_list);
400 fibril_mutex_unlock(&servers_list_mutex);
[a35b458]401
[a46e56b]402 async_answer_0(icall_handle, EOK);
[a35b458]403
[15f3c3f]404 return server;
405}
406
407/**
408 * Unregister server, unregister all its services and free server
409 * structure.
410 *
411 */
[5a6cc679]412static errno_t loc_server_unregister(loc_server_t *server)
[15f3c3f]413{
414 if (server == NULL)
[8a637a4]415 return EEXIST;
[a35b458]416
[15f3c3f]417 fibril_mutex_lock(&servers_list_mutex);
[a35b458]418
[15f3c3f]419 if (server->sess)
420 async_hangup(server->sess);
[a35b458]421
[15f3c3f]422 /* Remove it from list of servers */
423 list_remove(&(server->servers));
[a35b458]424
[15f3c3f]425 /* Unregister all its services */
426 fibril_mutex_lock(&services_list_mutex);
427 fibril_mutex_lock(&server->services_mutex);
[d0dd7b5]428 fibril_mutex_lock(&cdir.mutex);
[a35b458]429
[15f3c3f]430 while (!list_empty(&server->services)) {
431 loc_service_t *service = list_get_instance(
432 list_first(&server->services), loc_service_t,
433 server_services);
434 loc_service_unregister_core(service);
435 }
[a35b458]436
[d0dd7b5]437 fibril_mutex_unlock(&cdir.mutex);
[15f3c3f]438 fibril_mutex_unlock(&server->services_mutex);
439 fibril_mutex_unlock(&services_list_mutex);
440 fibril_mutex_unlock(&servers_list_mutex);
[a35b458]441
[15f3c3f]442 /* Free name and server */
443 if (server->name != NULL)
444 free(server->name);
[a35b458]445
[15f3c3f]446 free(server);
[a35b458]447
[3a9cf35]448 loc_category_change_event();
[15f3c3f]449 return EOK;
450}
451
452/** Register service
453 *
454 */
[a46e56b]455static void loc_service_register(cap_call_handle_t icall_handle, ipc_call_t *icall,
[15f3c3f]456 loc_server_t *server)
457{
458 if (server == NULL) {
[a46e56b]459 async_answer_0(icall_handle, EREFUSED);
[15f3c3f]460 return;
461 }
[a35b458]462
[15f3c3f]463 /* Create new service entry */
464 loc_service_t *service =
465 (loc_service_t *) malloc(sizeof(loc_service_t));
466 if (service == NULL) {
[a46e56b]467 async_answer_0(icall_handle, ENOMEM);
[15f3c3f]468 return;
469 }
[a35b458]470
[15f3c3f]471 /* Get fqsn */
472 char *fqsn;
[5a6cc679]473 errno_t rc = async_data_write_accept((void **) &fqsn, true, 0,
[15f3c3f]474 LOC_NAME_MAXLEN, 0, NULL);
475 if (rc != EOK) {
476 free(service);
[a46e56b]477 async_answer_0(icall_handle, rc);
[15f3c3f]478 return;
479 }
[a35b458]480
[15f3c3f]481 char *ns_name;
482 if (!loc_fqsn_split(fqsn, &ns_name, &service->name)) {
483 free(fqsn);
484 free(service);
[a46e56b]485 async_answer_0(icall_handle, EINVAL);
[15f3c3f]486 return;
487 }
[a35b458]488
[15f3c3f]489 free(fqsn);
[a35b458]490
[15f3c3f]491 fibril_mutex_lock(&services_list_mutex);
[a35b458]492
[15f3c3f]493 loc_namespace_t *namespace = loc_namespace_create(ns_name);
494 free(ns_name);
495 if (namespace == NULL) {
496 fibril_mutex_unlock(&services_list_mutex);
497 free(service->name);
498 free(service);
[a46e56b]499 async_answer_0(icall_handle, ENOMEM);
[15f3c3f]500 return;
501 }
[a35b458]502
[15f3c3f]503 link_initialize(&service->services);
504 link_initialize(&service->server_services);
[d0dd7b5]505 list_initialize(&service->cat_memb);
[a35b458]506
[15f3c3f]507 /* Check that service is not already registered */
508 if (loc_service_find_name(namespace->name, service->name) != NULL) {
509 printf("%s: Service '%s/%s' already registered\n", NAME,
510 namespace->name, service->name);
511 loc_namespace_destroy(namespace);
512 fibril_mutex_unlock(&services_list_mutex);
513 free(service->name);
514 free(service);
[a46e56b]515 async_answer_0(icall_handle, EEXIST);
[15f3c3f]516 return;
517 }
[a35b458]518
[15f3c3f]519 /* Get unique service ID */
520 service->id = loc_create_id();
521
522 loc_namespace_addref(namespace, service);
523 service->server = server;
[a35b458]524
[15f3c3f]525 /* Insert service into list of all services */
526 list_append(&service->services, &services_list);
[a35b458]527
[15f3c3f]528 /* Insert service into list of services supplied by one server */
529 fibril_mutex_lock(&service->server->services_mutex);
[a35b458]530
[15f3c3f]531 list_append(&service->server_services, &service->server->services);
[a35b458]532
[15f3c3f]533 fibril_mutex_unlock(&service->server->services_mutex);
534 fibril_condvar_broadcast(&services_list_cv);
535 fibril_mutex_unlock(&services_list_mutex);
[a35b458]536
[a46e56b]537 async_answer_1(icall_handle, EOK, service->id);
[15f3c3f]538}
539
540/**
541 *
542 */
[a46e56b]543static void loc_service_unregister(cap_call_handle_t icall_handle, ipc_call_t *icall,
[15f3c3f]544 loc_server_t *server)
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);
[a46e56b]552 async_answer_0(icall_handle, 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();
[a46e56b]567 async_answer_0(icall_handle, EOK);
[15f3c3f]568}
569
[a46e56b]570static void loc_category_get_name(cap_call_handle_t icall_handle, ipc_call_t *icall)
[763e0cd]571{
[a46e56b]572 cap_call_handle_t chandle;
[763e0cd]573 size_t size;
574 size_t act_size;
575 category_t *cat;
[a35b458]576
[a46e56b]577 if (!async_data_read_receive(&chandle, &size)) {
578 async_answer_0(chandle, EREFUSED);
579 async_answer_0(icall_handle, 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);
[a46e56b]588 async_answer_0(chandle, ENOENT);
589 async_answer_0(icall_handle, 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);
[a46e56b]596 async_answer_0(chandle, EOVERFLOW);
597 async_answer_0(icall_handle, EOVERFLOW);
[763e0cd]598 return;
599 }
[a35b458]600
[a46e56b]601 errno_t retval = async_data_read_finalize(chandle, cat->name,
[763e0cd]602 min(size, act_size));
[a35b458]603
[763e0cd]604 fibril_mutex_unlock(&cdir.mutex);
[a35b458]605
[a46e56b]606 async_answer_0(icall_handle, retval);
[763e0cd]607}
608
[a46e56b]609static void loc_service_get_name(cap_call_handle_t icall_handle, ipc_call_t *icall)
[cce8a83]610{
[a46e56b]611 cap_call_handle_t chandle;
[cce8a83]612 size_t size;
613 size_t act_size;
614 loc_service_t *svc;
[77a69ea]615 char *fqn;
[a35b458]616
[a46e56b]617 if (!async_data_read_receive(&chandle, &size)) {
618 async_answer_0(chandle, EREFUSED);
619 async_answer_0(icall_handle, 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);
[a46e56b]628 async_answer_0(chandle, ENOENT);
629 async_answer_0(icall_handle, 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);
[a46e56b]635 async_answer_0(chandle, ENOMEM);
636 async_answer_0(icall_handle, 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);
[a46e56b]644 async_answer_0(chandle, EOVERFLOW);
645 async_answer_0(icall_handle, EOVERFLOW);
[cce8a83]646 return;
647 }
[a35b458]648
[a46e56b]649 errno_t retval = async_data_read_finalize(chandle, fqn,
[cce8a83]650 min(size, act_size));
[77a69ea]651 free(fqn);
[a35b458]652
[cce8a83]653 fibril_mutex_unlock(&services_list_mutex);
[a35b458]654
[a46e56b]655 async_answer_0(icall_handle, retval);
[cce8a83]656}
657
[a46e56b]658static void loc_service_get_server_name(cap_call_handle_t icall_handle, ipc_call_t *icall)
[a3fcfba]659{
[a46e56b]660 cap_call_handle_t chandle;
[a3fcfba]661 size_t size;
662 size_t act_size;
663 loc_service_t *svc;
[a35b458]664
[a46e56b]665 if (!async_data_read_receive(&chandle, &size)) {
666 async_answer_0(chandle, EREFUSED);
667 async_answer_0(icall_handle, 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);
[a46e56b]676 async_answer_0(chandle, ENOENT);
677 async_answer_0(icall_handle, ENOENT);
[a3fcfba]678 return;
679 }
[a35b458]680
[a3fcfba]681 if (svc->server == NULL) {
682 fibril_mutex_unlock(&services_list_mutex);
[a46e56b]683 async_answer_0(chandle, EINVAL);
684 async_answer_0(icall_handle, 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);
[a46e56b]691 async_answer_0(chandle, EOVERFLOW);
692 async_answer_0(icall_handle, EOVERFLOW);
[a3fcfba]693 return;
694 }
[a35b458]695
[a46e56b]696 errno_t retval = async_data_read_finalize(chandle, svc->server->name,
[a3fcfba]697 min(size, act_size));
[a35b458]698
[a3fcfba]699 fibril_mutex_unlock(&services_list_mutex);
[a35b458]700
[a46e56b]701 async_answer_0(icall_handle, 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 */
[a46e56b]710static void loc_forward(cap_call_handle_t chandle, 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);
[a46e56b]723 async_answer_0(chandle, ENOENT);
[15f3c3f]724 return;
725 }
[a35b458]726
[15f3c3f]727 async_exch_t *exch = async_exchange_begin(svc->server->sess);
[a46e56b]728 async_forward_fast(chandle, 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 */
[a46e56b]740static void loc_service_get_id(cap_call_handle_t icall_handle, 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) {
[a46e56b]748 async_answer_0(icall_handle, 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);
[a46e56b]756 async_answer_0(icall_handle, 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
[a46e56b]783 async_answer_0(icall_handle, ENOENT);
[15f3c3f]784 free(ns_name);
785 free(name);
786 fibril_mutex_unlock(&services_list_mutex);
787 return;
788 }
[a35b458]789
[a46e56b]790 async_answer_1(icall_handle, 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 */
[a46e56b]803static void loc_namespace_get_id(cap_call_handle_t icall_handle, 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) {
[a46e56b]811 async_answer_0(icall_handle, 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
[a46e56b]836 async_answer_0(icall_handle, ENOENT);
[15f3c3f]837 free(name);
838 fibril_mutex_unlock(&services_list_mutex);
839 return;
840 }
[a35b458]841
[a46e56b]842 async_answer_1(icall_handle, 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 */
[a46e56b]857static void loc_callback_create(cap_call_handle_t icall_handle, 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) {
[a46e56b]861 async_answer_0(icall_handle, 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);
[a46e56b]868 async_answer_0(icall_handle, 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
[a46e56b]879 async_answer_0(icall_handle, 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 */
[a46e56b]901static void loc_category_get_id(cap_call_handle_t icall_handle, 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) {
[a46e56b]910 async_answer_0(icall_handle, 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 */
[a46e56b]919 async_answer_0(icall_handle, ENOENT);
[cc574511]920 goto cleanup;
921 }
[a35b458]922
[a46e56b]923 async_answer_1(icall_handle, EOK, cat->id);
[cc574511]924cleanup:
925 fibril_mutex_unlock(&cdir.mutex);
926 free(name);
927}
928
[a46e56b]929static void loc_id_probe(cap_call_handle_t icall_handle, 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)
[a46e56b]939 async_answer_1(icall_handle, EOK, LOC_OBJECT_NONE);
[15f3c3f]940 else
[a46e56b]941 async_answer_1(icall_handle, EOK, LOC_OBJECT_SERVICE);
[15f3c3f]942 } else
[a46e56b]943 async_answer_1(icall_handle, EOK, LOC_OBJECT_NAMESPACE);
[a35b458]944
[15f3c3f]945 fibril_mutex_unlock(&services_list_mutex);
946}
947
[a46e56b]948static void loc_get_namespace_count(cap_call_handle_t icall_handle, ipc_call_t *icall)
[15f3c3f]949{
950 fibril_mutex_lock(&services_list_mutex);
[a46e56b]951 async_answer_1(icall_handle, EOK, list_count(&namespaces_list));
[15f3c3f]952 fibril_mutex_unlock(&services_list_mutex);
953}
954
[a46e56b]955static void loc_get_service_count(cap_call_handle_t icall_handle, 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)
[a46e56b]962 async_answer_0(icall_handle, EEXIST);
[15f3c3f]963 else
[a46e56b]964 async_answer_1(icall_handle, EOK, namespace->refcnt);
[a35b458]965
[15f3c3f]966 fibril_mutex_unlock(&services_list_mutex);
967}
968
[a46e56b]969static void loc_get_categories(cap_call_handle_t icall_handle, ipc_call_t *icall)
[278ac72]970{
[a46e56b]971 cap_call_handle_t chandle;
[278ac72]972 size_t size;
973 size_t act_size;
[5a6cc679]974 errno_t rc;
[a35b458]975
[a46e56b]976 if (!async_data_read_receive(&chandle, &size)) {
977 async_answer_0(chandle, EREFUSED);
978 async_answer_0(icall_handle, 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);
[a46e56b]985 async_answer_0(chandle, ENOMEM);
986 async_answer_0(icall_handle, 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);
[a46e56b]995 async_answer_0(chandle, rc);
996 async_answer_0(icall_handle, rc);
[278ac72]997 return;
998 }
[a35b458]999
[278ac72]1000 fibril_mutex_unlock(&cdir.mutex);
[a35b458]1001
[a46e56b]1002 errno_t retval = async_data_read_finalize(chandle, id_buf, size);
[278ac72]1003 free(id_buf);
[a35b458]1004
[a46e56b]1005 async_answer_1(icall_handle, retval, act_size);
[278ac72]1006}
1007
[a46e56b]1008static void loc_get_namespaces(cap_call_handle_t icall_handle, ipc_call_t *icall)
[15f3c3f]1009{
[a46e56b]1010 cap_call_handle_t chandle;
[15f3c3f]1011 size_t size;
[a46e56b]1012 if (!async_data_read_receive(&chandle, &size)) {
1013 async_answer_0(chandle, EREFUSED);
1014 async_answer_0(icall_handle, EREFUSED);
[15f3c3f]1015 return;
1016 }
[a35b458]1017
[15f3c3f]1018 if ((size % sizeof(loc_sdesc_t)) != 0) {
[a46e56b]1019 async_answer_0(chandle, EINVAL);
1020 async_answer_0(icall_handle, 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);
[a46e56b]1029 async_answer_0(chandle, EOVERFLOW);
1030 async_answer_0(icall_handle, 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);
[a46e56b]1037 async_answer_0(chandle, ENOMEM);
1038 async_answer_0(icall_handle, 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
[a46e56b]1049 errno_t retval = async_data_read_finalize(chandle, desc, size);
[a35b458]1050
[15f3c3f]1051 free(desc);
1052 fibril_mutex_unlock(&services_list_mutex);
[a35b458]1053
[a46e56b]1054 async_answer_0(icall_handle, retval);
[15f3c3f]1055}
1056
[a46e56b]1057static void loc_get_services(cap_call_handle_t icall_handle, ipc_call_t *icall)
[15f3c3f]1058{
1059 /* FIXME: Use faster algorithm which can make better use
1060 of namespaces */
[a35b458]1061
[a46e56b]1062 cap_call_handle_t chandle;
[15f3c3f]1063 size_t size;
[a46e56b]1064 if (!async_data_read_receive(&chandle, &size)) {
1065 async_answer_0(chandle, EREFUSED);
1066 async_answer_0(icall_handle, EREFUSED);
[15f3c3f]1067 return;
1068 }
[a35b458]1069
[15f3c3f]1070 if ((size % sizeof(loc_sdesc_t)) != 0) {
[a46e56b]1071 async_answer_0(chandle, EINVAL);
1072 async_answer_0(icall_handle, EINVAL);
[15f3c3f]1073 return;
1074 }
[a35b458]1075
[15f3c3f]1076 fibril_mutex_lock(&services_list_mutex);
[a35b458]1077
[15f3c3f]1078 loc_namespace_t *namespace =
1079 loc_namespace_find_id(IPC_GET_ARG1(*icall));
1080 if (namespace == NULL) {
1081 fibril_mutex_unlock(&services_list_mutex);
[a46e56b]1082 async_answer_0(chandle, ENOENT);
1083 async_answer_0(icall_handle, ENOENT);
[15f3c3f]1084 return;
1085 }
[a35b458]1086
[15f3c3f]1087 size_t count = size / sizeof(loc_sdesc_t);
1088 if (count != namespace->refcnt) {
1089 fibril_mutex_unlock(&services_list_mutex);
[a46e56b]1090 async_answer_0(chandle, EOVERFLOW);
1091 async_answer_0(icall_handle, EOVERFLOW);
[15f3c3f]1092 return;
1093 }
[a35b458]1094
[15f3c3f]1095 loc_sdesc_t *desc = (loc_sdesc_t *) malloc(size);
1096 if (desc == NULL) {
1097 fibril_mutex_unlock(&services_list_mutex);
[a46e56b]1098 async_answer_0(chandle, ENOMEM);
1099 async_answer_0(icall_handle, EREFUSED);
[15f3c3f]1100 return;
1101 }
[a35b458]1102
[15f3c3f]1103 size_t pos = 0;
[feeac0d]1104 list_foreach(services_list, services, loc_service_t, service) {
[15f3c3f]1105 if (service->namespace == namespace) {
1106 desc[pos].id = service->id;
1107 str_cpy(desc[pos].name, LOC_NAME_MAXLEN, service->name);
1108 pos++;
1109 }
1110 }
[a35b458]1111
[a46e56b]1112 errno_t retval = async_data_read_finalize(chandle, desc, size);
[a35b458]1113
[15f3c3f]1114 free(desc);
1115 fibril_mutex_unlock(&services_list_mutex);
[a35b458]1116
[a46e56b]1117 async_answer_0(icall_handle, retval);
[15f3c3f]1118}
1119
[a46e56b]1120static void loc_category_get_svcs(cap_call_handle_t icall_handle, ipc_call_t *icall)
[cc574511]1121{
[a46e56b]1122 cap_call_handle_t chandle;
[cc574511]1123 size_t size;
1124 size_t act_size;
[5a6cc679]1125 errno_t rc;
[a35b458]1126
[a46e56b]1127 if (!async_data_read_receive(&chandle, &size)) {
1128 async_answer_0(chandle, EREFUSED);
1129 async_answer_0(icall_handle, EREFUSED);
[cc574511]1130 return;
1131 }
[a35b458]1132
[cc574511]1133 fibril_mutex_lock(&cdir.mutex);
[a35b458]1134
[cc574511]1135 category_t *cat = category_get(&cdir, IPC_GET_ARG1(*icall));
1136 if (cat == NULL) {
1137 fibril_mutex_unlock(&cdir.mutex);
[a46e56b]1138 async_answer_0(chandle, ENOENT);
1139 async_answer_0(icall_handle, ENOENT);
[cc574511]1140 return;
1141 }
[a35b458]1142
[cc574511]1143 category_id_t *id_buf = (category_id_t *) malloc(size);
1144 if (id_buf == NULL) {
1145 fibril_mutex_unlock(&cdir.mutex);
[a46e56b]1146 async_answer_0(chandle, ENOMEM);
1147 async_answer_0(icall_handle, ENOMEM);
[cc574511]1148 return;
1149 }
[a35b458]1150
[cc574511]1151 fibril_mutex_lock(&cat->mutex);
[a35b458]1152
[cc574511]1153 rc = category_get_services(cat, id_buf, size, &act_size);
1154 if (rc != EOK) {
1155 fibril_mutex_unlock(&cat->mutex);
1156 fibril_mutex_unlock(&cdir.mutex);
[a46e56b]1157 async_answer_0(chandle, rc);
1158 async_answer_0(icall_handle, rc);
[cc574511]1159 return;
1160 }
[a35b458]1161
[cc574511]1162 fibril_mutex_unlock(&cat->mutex);
1163 fibril_mutex_unlock(&cdir.mutex);
[a35b458]1164
[a46e56b]1165 errno_t retval = async_data_read_finalize(chandle, id_buf, size);
[cc574511]1166 free(id_buf);
[a35b458]1167
[a46e56b]1168 async_answer_1(icall_handle, retval, act_size);
[cc574511]1169}
1170
1171
[a46e56b]1172static void loc_null_create(cap_call_handle_t icall_handle, ipc_call_t *icall)
[15f3c3f]1173{
1174 fibril_mutex_lock(&null_services_mutex);
[a35b458]1175
[15f3c3f]1176 unsigned int i;
1177 bool fnd = false;
[a35b458]1178
[15f3c3f]1179 for (i = 0; i < NULL_SERVICES; i++) {
1180 if (null_services[i] == NULL) {
1181 fnd = true;
1182 break;
1183 }
1184 }
[a35b458]1185
[15f3c3f]1186 if (!fnd) {
1187 fibril_mutex_unlock(&null_services_mutex);
[a46e56b]1188 async_answer_0(icall_handle, ENOMEM);
[15f3c3f]1189 return;
1190 }
[a35b458]1191
[15f3c3f]1192 char null[LOC_NAME_MAXLEN];
1193 snprintf(null, LOC_NAME_MAXLEN, "%u", i);
[a35b458]1194
[15f3c3f]1195 char *dev_name = str_dup(null);
1196 if (dev_name == NULL) {
1197 fibril_mutex_unlock(&null_services_mutex);
[a46e56b]1198 async_answer_0(icall_handle, ENOMEM);
[15f3c3f]1199 return;
1200 }
[a35b458]1201
[15f3c3f]1202 loc_service_t *service =
1203 (loc_service_t *) malloc(sizeof(loc_service_t));
1204 if (service == NULL) {
1205 fibril_mutex_unlock(&null_services_mutex);
[a46e56b]1206 async_answer_0(icall_handle, ENOMEM);
[15f3c3f]1207 return;
1208 }
[a35b458]1209
[15f3c3f]1210 fibril_mutex_lock(&services_list_mutex);
[a35b458]1211
[15f3c3f]1212 loc_namespace_t *namespace = loc_namespace_create("null");
1213 if (namespace == NULL) {
1214 fibril_mutex_lock(&services_list_mutex);
1215 fibril_mutex_unlock(&null_services_mutex);
[a46e56b]1216 async_answer_0(icall_handle, ENOMEM);
[15f3c3f]1217 return;
1218 }
[a35b458]1219
[15f3c3f]1220 link_initialize(&service->services);
1221 link_initialize(&service->server_services);
[03f4acf]1222 list_initialize(&service->cat_memb);
[a35b458]1223
[15f3c3f]1224 /* Get unique service ID */
1225 service->id = loc_create_id();
1226 service->server = NULL;
[a35b458]1227
[15f3c3f]1228 loc_namespace_addref(namespace, service);
1229 service->name = dev_name;
[a35b458]1230
[15f3c3f]1231 /*
1232 * Insert service into list of all services and into null services array.
1233 * Insert service into a dummy list of null server's services so that it
1234 * can be safely removed later.
1235 */
1236 list_append(&service->services, &services_list);
1237 list_append(&service->server_services, &dummy_null_services);
1238 null_services[i] = service;
[a35b458]1239
[15f3c3f]1240 fibril_mutex_unlock(&services_list_mutex);
1241 fibril_mutex_unlock(&null_services_mutex);
[a35b458]1242
[a46e56b]1243 async_answer_1(icall_handle, EOK, (sysarg_t) i);
[15f3c3f]1244}
1245
[a46e56b]1246static void loc_null_destroy(cap_call_handle_t icall_handle, ipc_call_t *icall)
[15f3c3f]1247{
1248 sysarg_t i = IPC_GET_ARG1(*icall);
1249 if (i >= NULL_SERVICES) {
[a46e56b]1250 async_answer_0(icall_handle, ELIMIT);
[15f3c3f]1251 return;
1252 }
[a35b458]1253
[15f3c3f]1254 fibril_mutex_lock(&null_services_mutex);
[a35b458]1255
[15f3c3f]1256 if (null_services[i] == NULL) {
1257 fibril_mutex_unlock(&null_services_mutex);
[a46e56b]1258 async_answer_0(icall_handle, ENOENT);
[15f3c3f]1259 return;
1260 }
[a35b458]1261
[15f3c3f]1262 fibril_mutex_lock(&services_list_mutex);
[d0dd7b5]1263 fibril_mutex_lock(&cdir.mutex);
[15f3c3f]1264 loc_service_unregister_core(null_services[i]);
[d0dd7b5]1265 fibril_mutex_unlock(&cdir.mutex);
[15f3c3f]1266 fibril_mutex_unlock(&services_list_mutex);
[a35b458]1267
[15f3c3f]1268 null_services[i] = NULL;
[a35b458]1269
[15f3c3f]1270 fibril_mutex_unlock(&null_services_mutex);
[a46e56b]1271 async_answer_0(icall_handle, EOK);
[15f3c3f]1272}
1273
[a46e56b]1274static void loc_service_add_to_cat(cap_call_handle_t icall_handle, ipc_call_t *icall)
[cc574511]1275{
1276 category_t *cat;
1277 loc_service_t *svc;
1278 catid_t cat_id;
1279 service_id_t svc_id;
[5a6cc679]1280 errno_t retval;
[a35b458]1281
[cc574511]1282 svc_id = IPC_GET_ARG1(*icall);
1283 cat_id = IPC_GET_ARG2(*icall);
[a35b458]1284
[cc574511]1285 fibril_mutex_lock(&services_list_mutex);
1286 fibril_mutex_lock(&cdir.mutex);
[a35b458]1287
[cc574511]1288 cat = category_get(&cdir, cat_id);
1289 svc = loc_service_find_id(svc_id);
[a35b458]1290
[aff587f]1291 if (cat == NULL || svc == NULL) {
1292 fibril_mutex_unlock(&cdir.mutex);
1293 fibril_mutex_unlock(&services_list_mutex);
[a46e56b]1294 async_answer_0(icall_handle, ENOENT);
[aff587f]1295 return;
1296 }
[a35b458]1297
[cc574511]1298 fibril_mutex_lock(&cat->mutex);
1299 retval = category_add_service(cat, svc);
1300
1301 fibril_mutex_unlock(&cat->mutex);
1302 fibril_mutex_unlock(&cdir.mutex);
1303 fibril_mutex_unlock(&services_list_mutex);
1304
[adb1ae9]1305 /*
1306 * First send out all notifications and only then answer the request.
1307 * Otherwise the current fibril might block and transitively wait for
1308 * the completion of requests that are routed to it via an IPC loop.
1309 */
[12f9f0d0]1310 loc_category_change_event();
[a46e56b]1311 async_answer_0(icall_handle, retval);
[cc574511]1312}
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 */
[a46e56b]1395static void loc_connection_supplier(cap_call_handle_t icall_handle, ipc_call_t *icall, void *arg)
[15f3c3f]1396{
1397 /* Accept connection */
[a46e56b]1398 async_answer_0(icall_handle, EOK);
[a35b458]1399
[15f3c3f]1400 loc_server_t *server = loc_server_register();
1401 if (server == NULL)
1402 return;
[a35b458]1403
[15f3c3f]1404 while (true) {
1405 ipc_call_t call;
[a46e56b]1406 cap_call_handle_t chandle = async_get_call(&call);
[a35b458]1407
[15f3c3f]1408 if (!IPC_GET_IMETHOD(call))
1409 break;
[a35b458]1410
[15f3c3f]1411 switch (IPC_GET_IMETHOD(call)) {
1412 case LOC_SERVER_UNREGISTER:
1413 if (server == NULL)
[a46e56b]1414 async_answer_0(chandle, ENOENT);
[15f3c3f]1415 else
[a46e56b]1416 async_answer_0(chandle, EOK);
[15f3c3f]1417 break;
[cc574511]1418 case LOC_SERVICE_ADD_TO_CAT:
1419 /* Add service to category */
[a46e56b]1420 loc_service_add_to_cat(chandle, &call);
[cc574511]1421 break;
[15f3c3f]1422 case LOC_SERVICE_REGISTER:
1423 /* Register one service */
[a46e56b]1424 loc_service_register(chandle, &call, server);
[15f3c3f]1425 break;
1426 case LOC_SERVICE_UNREGISTER:
1427 /* Remove one service */
[a46e56b]1428 loc_service_unregister(chandle, &call, server);
[15f3c3f]1429 break;
1430 case LOC_SERVICE_GET_ID:
[a46e56b]1431 loc_service_get_id(chandle, &call);
[15f3c3f]1432 break;
1433 case LOC_NAMESPACE_GET_ID:
[a46e56b]1434 loc_namespace_get_id(chandle, &call);
[15f3c3f]1435 break;
1436 default:
[a46e56b]1437 async_answer_0(chandle, ENOENT);
[15f3c3f]1438 }
1439 }
[a35b458]1440
[15f3c3f]1441 if (server != NULL) {
1442 /*
1443 * Unregister the server and all its services.
1444 */
1445 loc_server_unregister(server);
1446 server = NULL;
1447 }
1448}
1449
1450/** Handle connection on consumer port.
1451 *
1452 */
[a46e56b]1453static void loc_connection_consumer(cap_call_handle_t icall_handle, ipc_call_t *icall, void *arg)
[15f3c3f]1454{
1455 /* Accept connection */
[a46e56b]1456 async_answer_0(icall_handle, EOK);
[a35b458]1457
[15f3c3f]1458 while (true) {
1459 ipc_call_t call;
[a46e56b]1460 cap_call_handle_t chandle = async_get_call(&call);
[a35b458]1461
[15f3c3f]1462 if (!IPC_GET_IMETHOD(call))
1463 break;
[a35b458]1464
[15f3c3f]1465 switch (IPC_GET_IMETHOD(call)) {
1466 case LOC_SERVICE_GET_ID:
[a46e56b]1467 loc_service_get_id(chandle, &call);
[15f3c3f]1468 break;
[cce8a83]1469 case LOC_SERVICE_GET_NAME:
[a46e56b]1470 loc_service_get_name(chandle, &call);
[cce8a83]1471 break;
[a3fcfba]1472 case LOC_SERVICE_GET_SERVER_NAME:
[a46e56b]1473 loc_service_get_server_name(chandle, &call);
[a3fcfba]1474 break;
[15f3c3f]1475 case LOC_NAMESPACE_GET_ID:
[a46e56b]1476 loc_namespace_get_id(chandle, &call);
[15f3c3f]1477 break;
[12f9f0d0]1478 case LOC_CALLBACK_CREATE:
[a46e56b]1479 loc_callback_create(chandle, &call);
[12f9f0d0]1480 break;
[cc574511]1481 case LOC_CATEGORY_GET_ID:
[a46e56b]1482 loc_category_get_id(chandle, &call);
[cc574511]1483 break;
[763e0cd]1484 case LOC_CATEGORY_GET_NAME:
[a46e56b]1485 loc_category_get_name(chandle, &call);
[763e0cd]1486 break;
[cc574511]1487 case LOC_CATEGORY_GET_SVCS:
[a46e56b]1488 loc_category_get_svcs(chandle, &call);
[cc574511]1489 break;
[15f3c3f]1490 case LOC_ID_PROBE:
[a46e56b]1491 loc_id_probe(chandle, &call);
[15f3c3f]1492 break;
1493 case LOC_NULL_CREATE:
[a46e56b]1494 loc_null_create(chandle, &call);
[15f3c3f]1495 break;
1496 case LOC_NULL_DESTROY:
[a46e56b]1497 loc_null_destroy(chandle, &call);
[15f3c3f]1498 break;
1499 case LOC_GET_NAMESPACE_COUNT:
[a46e56b]1500 loc_get_namespace_count(chandle, &call);
[15f3c3f]1501 break;
1502 case LOC_GET_SERVICE_COUNT:
[a46e56b]1503 loc_get_service_count(chandle, &call);
[15f3c3f]1504 break;
[278ac72]1505 case LOC_GET_CATEGORIES:
[a46e56b]1506 loc_get_categories(chandle, &call);
[278ac72]1507 break;
[15f3c3f]1508 case LOC_GET_NAMESPACES:
[a46e56b]1509 loc_get_namespaces(chandle, &call);
[15f3c3f]1510 break;
1511 case LOC_GET_SERVICES:
[a46e56b]1512 loc_get_services(chandle, &call);
[15f3c3f]1513 break;
1514 default:
[a46e56b]1515 async_answer_0(chandle, ENOENT);
[15f3c3f]1516 }
1517 }
1518}
1519
1520/**
1521 *
1522 */
1523int main(int argc, char *argv[])
1524{
1525 printf("%s: HelenOS Location Service\n", NAME);
[a35b458]1526
[15f3c3f]1527 if (!loc_init()) {
1528 printf("%s: Error while initializing service\n", NAME);
1529 return -1;
1530 }
[a35b458]1531
[f9b2cb4c]1532 port_id_t port;
[5a6cc679]1533 errno_t rc = async_create_port(INTERFACE_LOC_SUPPLIER,
[f9b2cb4c]1534 loc_connection_supplier, NULL, &port);
[c1694b6b]1535 if (rc != EOK) {
1536 printf("%s: Error while creating supplier port: %s\n", NAME, str_error(rc));
[f9b2cb4c]1537 return rc;
[c1694b6b]1538 }
[a35b458]1539
[f9b2cb4c]1540 rc = async_create_port(INTERFACE_LOC_CONSUMER,
1541 loc_connection_consumer, NULL, &port);
[c1694b6b]1542 if (rc != EOK) {
1543 printf("%s: Error while creating consumer port: %s\n", NAME, str_error(rc));
[f9b2cb4c]1544 return rc;
[c1694b6b]1545 }
[a35b458]1546
[15f3c3f]1547 /* Set a handler of incomming connections */
[f9b2cb4c]1548 async_set_fallback_port_handler(loc_forward, NULL);
[a35b458]1549
[15f3c3f]1550 /* Register location service at naming service */
[f9b2cb4c]1551 rc = service_register(SERVICE_LOC);
[c1694b6b]1552 if (rc != EOK) {
1553 printf("%s: Error while registering service: %s\n", NAME, str_error(rc));
[50ad3f3]1554 return rc;
[c1694b6b]1555 }
[a35b458]1556
[15f3c3f]1557 printf("%s: Accepting connections\n", NAME);
1558 async_manager();
[a35b458]1559
[15f3c3f]1560 /* Never reached */
1561 return 0;
1562}
1563
1564/**
1565 * @}
1566 */
Note: See TracBrowser for help on using the repository browser.