source: mainline/uspace/srv/ns/service.c@ 65706f1

Last change on this file since 65706f1 was 61eb2ce2, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Make hash table operations immutable, because global mutable state is evil

  • Property mode set to 100644
File size: 10.2 KB
RevLine 
[40313e4]1/*
2 * Copyright (c) 2009 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup ns
30 * @{
31 */
32
[d9c8c81]33#include <adt/hash_table.h>
[40313e4]34#include <assert.h>
[7b616e2]35#include <async.h>
[40313e4]36#include <errno.h>
[c7bbf029]37#include <stdio.h>
[38d150e]38#include <stdlib.h>
[40313e4]39#include "service.h"
40#include "ns.h"
41
42/** Service hash table item. */
43typedef struct {
[062d900]44 ht_link_t link;
[a35b458]45
[9cfbf2f]46 /** Service ID */
47 service_t service;
[a35b458]48
[9b1baac]49 /** Interface hash table */
50 hash_table_t iface_hash_table;
51
52 /** Broker session to the service */
53 async_sess_t *broker_sess;
54} hashed_service_t;
55
56/** Interface hash table item. */
57typedef struct {
58 ht_link_t link;
59
60 /** Interface ID */
61 iface_t iface;
62
[7b616e2]63 /** Session to the service */
64 async_sess_t *sess;
[9b1baac]65} hashed_iface_t;
[40313e4]66
[5e801dc]67static size_t service_key_hash(const void *key)
[40313e4]68{
[5e801dc]69 const service_t *srv = key;
70 return *srv;
[40313e4]71}
72
[062d900]73static size_t service_hash(const ht_link_t *item)
[40313e4]74{
[9cfbf2f]75 hashed_service_t *service =
76 hash_table_get_inst(item, hashed_service_t, link);
[a35b458]77
[9cfbf2f]78 return service->service;
[40313e4]79}
80
[5e801dc]81static bool service_key_equal(const void *key, const ht_link_t *item)
[40313e4]82{
[5e801dc]83 const service_t *srv = key;
[9cfbf2f]84 hashed_service_t *service =
85 hash_table_get_inst(item, hashed_service_t, link);
[a35b458]86
[5e801dc]87 return service->service == *srv;
[40313e4]88}
89
[5e801dc]90static size_t iface_key_hash(const void *key)
[9b1baac]91{
[5e801dc]92 const iface_t *iface = key;
93 return *iface;
[9b1baac]94}
95
96static size_t iface_hash(const ht_link_t *item)
97{
98 hashed_iface_t *iface =
99 hash_table_get_inst(item, hashed_iface_t, link);
100
101 return iface->iface;
102}
103
[5e801dc]104static bool iface_key_equal(const void *key, const ht_link_t *item)
[9b1baac]105{
[5e801dc]106 const iface_t *kiface = key;
[9b1baac]107 hashed_iface_t *iface =
108 hash_table_get_inst(item, hashed_iface_t, link);
109
[5e801dc]110 return iface->iface == *kiface;
[9b1baac]111}
112
[40313e4]113/** Operations for service hash table. */
[61eb2ce2]114static const hash_table_ops_t service_hash_table_ops = {
[40313e4]115 .hash = service_hash,
[062d900]116 .key_hash = service_key_hash,
117 .key_equal = service_key_equal,
[4e00f87]118 .equal = NULL,
119 .remove_callback = NULL
[40313e4]120};
121
[9b1baac]122/** Operations for interface hash table. */
[61eb2ce2]123static const hash_table_ops_t iface_hash_table_ops = {
[9b1baac]124 .hash = iface_hash,
125 .key_hash = iface_key_hash,
126 .key_equal = iface_key_equal,
127 .equal = NULL,
128 .remove_callback = NULL
129};
130
[40313e4]131/** Service hash table structure. */
132static hash_table_t service_hash_table;
133
134/** Pending connection structure. */
135typedef struct {
136 link_t link;
[a46e56b]137 service_t service; /**< Service ID */
138 iface_t iface; /**< Interface ID */
[984a9ba]139 ipc_call_t call; /**< Call waiting for the connection */
[40313e4]140} pending_conn_t;
141
[b72efe8]142static list_t pending_conn;
[40313e4]143
[9b1baac]144errno_t ns_service_init(void)
[40313e4]145{
[9cfbf2f]146 if (!hash_table_create(&service_hash_table, 0, 0,
147 &service_hash_table_ops)) {
148 printf("%s: No memory available for services\n", NAME);
[40313e4]149 return ENOMEM;
150 }
[a35b458]151
[40313e4]152 list_initialize(&pending_conn);
[a35b458]153
[40313e4]154 return EOK;
155}
156
[9b1baac]157static void ns_forward(async_sess_t *sess, ipc_call_t *call, iface_t iface)
158{
159 async_exch_t *exch = async_exchange_begin(sess);
[fafb8e5]160 async_forward_1(call, exch, iface, ipc_get_arg3(call), IPC_FF_NONE);
[9b1baac]161 async_exchange_end(exch);
162}
163
[40313e4]164/** Process pending connection requests */
[9b1baac]165void ns_pending_conn_process(void)
[40313e4]166{
167loop:
[9cfbf2f]168 list_foreach(pending_conn, link, pending_conn_t, pending) {
[9b1baac]169 ht_link_t *link =
170 hash_table_find(&service_hash_table, &pending->service);
[40313e4]171 if (!link)
172 continue;
[a35b458]173
[9b1baac]174 hashed_service_t *hashed_service =
175 hash_table_get_inst(link, hashed_service_t, link);
176
177 link = hash_table_find(&hashed_service->iface_hash_table,
178 &pending->iface);
179 if (!link) {
180 if (hashed_service->broker_sess != NULL) {
181 ns_forward(hashed_service->broker_sess, &pending->call,
182 pending->iface);
183
184 list_remove(&pending->link);
185 free(pending);
186
187 goto loop;
188 }
189
190 continue;
191 }
192
193 hashed_iface_t *hashed_iface =
194 hash_table_get_inst(link, hashed_iface_t, link);
195
196 ns_forward(hashed_iface->sess, &pending->call, pending->iface);
[a35b458]197
[9cfbf2f]198 list_remove(&pending->link);
199 free(pending);
[a35b458]200
[40313e4]201 goto loop;
202 }
203}
204
[9b1baac]205/** Register interface to a service.
206 *
207 * @param service Service to which the interface belongs.
208 * @param iface Interface to be registered.
209 *
210 * @return Zero on success or a value from @ref errno.h.
211 *
212 */
213static errno_t ns_iface_register(hashed_service_t *hashed_service, iface_t iface)
214{
215 ht_link_t *link = hash_table_find(&hashed_service->iface_hash_table,
216 &iface);
217 if (link)
218 return EEXIST;
219
220 hashed_iface_t *hashed_iface =
221 (hashed_iface_t *) malloc(sizeof(hashed_iface_t));
222 if (!hashed_iface)
223 return ENOMEM;
224
225 hashed_iface->iface = iface;
226 hashed_iface->sess = async_callback_receive(EXCHANGE_SERIALIZE);
227 if (hashed_iface->sess == NULL) {
228 free(hashed_iface);
229 return EIO;
230 }
231
232 hash_table_insert(&hashed_service->iface_hash_table,
233 &hashed_iface->link);
234 return EOK;
235}
236
237/** Register broker to a service.
238 *
239 * @param service Service to which the broker belongs.
240 *
241 * @return Zero on success or a value from @ref errno.h.
242 *
243 */
244static errno_t ns_broker_register(hashed_service_t *hashed_service)
245{
246 if (hashed_service->broker_sess != NULL)
247 return EEXIST;
248
249 hashed_service->broker_sess = async_callback_receive(EXCHANGE_SERIALIZE);
250 if (hashed_service->broker_sess == NULL)
251 return EIO;
252
253 return EOK;
254}
255
[40313e4]256/** Register service.
257 *
258 * @param service Service to be registered.
[9b1baac]259 * @param iface Interface to be registered.
[40313e4]260 *
261 * @return Zero on success or a value from @ref errno.h.
262 *
263 */
[9b1baac]264errno_t ns_service_register(service_t service, iface_t iface)
[40313e4]265{
[9b1baac]266 ht_link_t *link = hash_table_find(&service_hash_table, &service);
267
268 if (link) {
269 hashed_service_t *hashed_service =
270 hash_table_get_inst(link, hashed_service_t, link);
271
272 assert(hashed_service->service == service);
273
274 return ns_iface_register(hashed_service, iface);
275 }
[a35b458]276
[9cfbf2f]277 hashed_service_t *hashed_service =
278 (hashed_service_t *) malloc(sizeof(hashed_service_t));
279 if (!hashed_service)
[40313e4]280 return ENOMEM;
[a35b458]281
[9b1baac]282 if (!hash_table_create(&hashed_service->iface_hash_table, 0, 0,
283 &iface_hash_table_ops)) {
284 free(hashed_service);
285 return ENOMEM;
286 }
287
288 hashed_service->broker_sess = NULL;
[9cfbf2f]289 hashed_service->service = service;
[9b1baac]290 errno_t rc = ns_iface_register(hashed_service, iface);
291 if (rc != EOK) {
292 free(hashed_service);
293 return rc;
294 }
[a35b458]295
[9cfbf2f]296 hash_table_insert(&service_hash_table, &hashed_service->link);
[007e6efa]297 return EOK;
[40313e4]298}
299
[9b1baac]300/** Register broker service.
301 *
302 * @param service Broker service to be registered.
303 *
304 * @return Zero on success or a value from @ref errno.h.
305 *
306 */
307errno_t ns_service_register_broker(service_t service)
308{
309 ht_link_t *link = hash_table_find(&service_hash_table, &service);
310
311 if (link) {
312 hashed_service_t *hashed_service =
313 hash_table_get_inst(link, hashed_service_t, link);
314
315 assert(hashed_service->service == service);
316
317 return ns_broker_register(hashed_service);
318 }
319
320 hashed_service_t *hashed_service =
321 (hashed_service_t *) malloc(sizeof(hashed_service_t));
322 if (!hashed_service)
323 return ENOMEM;
324
325 if (!hash_table_create(&hashed_service->iface_hash_table, 0, 0,
326 &iface_hash_table_ops)) {
327 free(hashed_service);
328 return ENOMEM;
329 }
330
331 hashed_service->broker_sess = NULL;
332 hashed_service->service = service;
333 errno_t rc = ns_broker_register(hashed_service);
334 if (rc != EOK) {
335 free(hashed_service);
336 return rc;
337 }
338
339 hash_table_insert(&service_hash_table, &hashed_service->link);
340 return EOK;
341}
342
343/** Add pending connection */
344static errno_t ns_pending_conn_add(service_t service, iface_t iface,
345 ipc_call_t *call)
346{
347 pending_conn_t *pending =
348 (pending_conn_t *) malloc(sizeof(pending_conn_t));
349 if (!pending)
350 return ENOMEM;
351
352 link_initialize(&pending->link);
353 pending->service = service;
354 pending->iface = iface;
355 pending->call = *call;
356
357 list_append(&pending->link, &pending_conn);
358 return EOK;
359}
360
[40313e4]361/** Connect client to service.
362 *
[eed4139]363 * @param service Service to be connected to.
364 * @param iface Interface to be connected to.
365 * @param call Pointer to call structure.
[40313e4]366 *
367 * @return Zero on success or a value from @ref errno.h.
368 *
369 */
[9b1baac]370void ns_service_forward(service_t service, iface_t iface, ipc_call_t *call)
[40313e4]371{
[fafb8e5]372 sysarg_t flags = ipc_get_arg4(call);
[b7fd2a0]373 errno_t retval;
[a35b458]374
[062d900]375 ht_link_t *link = hash_table_find(&service_hash_table, &service);
[40313e4]376 if (!link) {
[9cfbf2f]377 if (flags & IPC_FLAG_BLOCKING) {
[40313e4]378 /* Blocking connection, add to pending list */
[9b1baac]379 errno_t rc = ns_pending_conn_add(service, iface, call);
380 if (rc == EOK)
381 return;
[a35b458]382
[9b1baac]383 retval = rc;
384 goto out;
385 }
386
387 retval = ENOENT;
388 goto out;
389 }
390
391 hashed_service_t *hashed_service =
392 hash_table_get_inst(link, hashed_service_t, link);
[a35b458]393
[9b1baac]394 link = hash_table_find(&hashed_service->iface_hash_table, &iface);
395 if (!link) {
396 if (hashed_service->broker_sess != NULL) {
397 ns_forward(hashed_service->broker_sess, call, iface);
[40313e4]398 return;
399 }
[a35b458]400
[9b1baac]401 if (flags & IPC_FLAG_BLOCKING) {
402 /* Blocking connection, add to pending list */
403 errno_t rc = ns_pending_conn_add(service, iface, call);
404 if (rc == EOK)
405 return;
406
407 retval = rc;
408 goto out;
409 }
410
[40313e4]411 retval = ENOENT;
412 goto out;
413 }
[a35b458]414
[9b1baac]415 hashed_iface_t *hashed_iface =
416 hash_table_get_inst(link, hashed_iface_t, link);
417
418 ns_forward(hashed_iface->sess, call, iface);
[c638c07]419 return;
[a35b458]420
[40313e4]421out:
[984a9ba]422 async_answer_0(call, retval);
[40313e4]423}
424
425/**
426 * @}
427 */
Note: See TracBrowser for help on using the repository browser.