source: mainline/uspace/srv/ns/service.c@ 3875f106

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

ns: register service interfaces individually

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

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

  • Property mode set to 100644
File size: 10.1 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
[062d900]67static size_t service_key_hash(void *key)
[40313e4]68{
[9cfbf2f]69 return *(service_t *) key;
[40313e4]70}
71
[062d900]72static size_t service_hash(const ht_link_t *item)
[40313e4]73{
[9cfbf2f]74 hashed_service_t *service =
75 hash_table_get_inst(item, hashed_service_t, link);
[a35b458]76
[9cfbf2f]77 return service->service;
[40313e4]78}
79
[062d900]80static bool service_key_equal(void *key, const ht_link_t *item)
[40313e4]81{
[9cfbf2f]82 hashed_service_t *service =
83 hash_table_get_inst(item, hashed_service_t, link);
[a35b458]84
[9cfbf2f]85 return service->service == *(service_t *) key;
[40313e4]86}
87
[9b1baac]88static size_t iface_key_hash(void *key)
89{
90 return *(iface_t *) key;
91}
92
93static size_t iface_hash(const ht_link_t *item)
94{
95 hashed_iface_t *iface =
96 hash_table_get_inst(item, hashed_iface_t, link);
97
98 return iface->iface;
99}
100
101static bool iface_key_equal(void *key, const ht_link_t *item)
102{
103 hashed_iface_t *iface =
104 hash_table_get_inst(item, hashed_iface_t, link);
105
106 return iface->iface == *(iface_t *) key;
107}
108
[40313e4]109/** Operations for service hash table. */
[062d900]110static hash_table_ops_t service_hash_table_ops = {
[40313e4]111 .hash = service_hash,
[062d900]112 .key_hash = service_key_hash,
113 .key_equal = service_key_equal,
[4e00f87]114 .equal = NULL,
115 .remove_callback = NULL
[40313e4]116};
117
[9b1baac]118/** Operations for interface hash table. */
119static hash_table_ops_t iface_hash_table_ops = {
120 .hash = iface_hash,
121 .key_hash = iface_key_hash,
122 .key_equal = iface_key_equal,
123 .equal = NULL,
124 .remove_callback = NULL
125};
126
[40313e4]127/** Service hash table structure. */
128static hash_table_t service_hash_table;
129
130/** Pending connection structure. */
131typedef struct {
132 link_t link;
[a46e56b]133 service_t service; /**< Service ID */
134 iface_t iface; /**< Interface ID */
[984a9ba]135 ipc_call_t call; /**< Call waiting for the connection */
[40313e4]136} pending_conn_t;
137
[b72efe8]138static list_t pending_conn;
[40313e4]139
[9b1baac]140errno_t ns_service_init(void)
[40313e4]141{
[9cfbf2f]142 if (!hash_table_create(&service_hash_table, 0, 0,
143 &service_hash_table_ops)) {
144 printf("%s: No memory available for services\n", NAME);
[40313e4]145 return ENOMEM;
146 }
[a35b458]147
[40313e4]148 list_initialize(&pending_conn);
[a35b458]149
[40313e4]150 return EOK;
151}
152
[9b1baac]153static void ns_forward(async_sess_t *sess, ipc_call_t *call, iface_t iface)
154{
155 async_exch_t *exch = async_exchange_begin(sess);
156 async_forward_fast(call, exch, iface, IPC_GET_ARG3(*call), 0,
157 IPC_FF_NONE);
158 async_exchange_end(exch);
159}
160
[40313e4]161/** Process pending connection requests */
[9b1baac]162void ns_pending_conn_process(void)
[40313e4]163{
164loop:
[9cfbf2f]165 list_foreach(pending_conn, link, pending_conn_t, pending) {
[9b1baac]166 ht_link_t *link =
167 hash_table_find(&service_hash_table, &pending->service);
[40313e4]168 if (!link)
169 continue;
[a35b458]170
[9b1baac]171 hashed_service_t *hashed_service =
172 hash_table_get_inst(link, hashed_service_t, link);
173
174 link = hash_table_find(&hashed_service->iface_hash_table,
175 &pending->iface);
176 if (!link) {
177 if (hashed_service->broker_sess != NULL) {
178 ns_forward(hashed_service->broker_sess, &pending->call,
179 pending->iface);
180
181 list_remove(&pending->link);
182 free(pending);
183
184 goto loop;
185 }
186
187 continue;
188 }
189
190 hashed_iface_t *hashed_iface =
191 hash_table_get_inst(link, hashed_iface_t, link);
192
193 ns_forward(hashed_iface->sess, &pending->call, pending->iface);
[a35b458]194
[9cfbf2f]195 list_remove(&pending->link);
196 free(pending);
[a35b458]197
[40313e4]198 goto loop;
199 }
200}
201
[9b1baac]202/** Register interface to a service.
203 *
204 * @param service Service to which the interface belongs.
205 * @param iface Interface to be registered.
206 *
207 * @return Zero on success or a value from @ref errno.h.
208 *
209 */
210static errno_t ns_iface_register(hashed_service_t *hashed_service, iface_t iface)
211{
212 ht_link_t *link = hash_table_find(&hashed_service->iface_hash_table,
213 &iface);
214 if (link)
215 return EEXIST;
216
217 hashed_iface_t *hashed_iface =
218 (hashed_iface_t *) malloc(sizeof(hashed_iface_t));
219 if (!hashed_iface)
220 return ENOMEM;
221
222 hashed_iface->iface = iface;
223 hashed_iface->sess = async_callback_receive(EXCHANGE_SERIALIZE);
224 if (hashed_iface->sess == NULL) {
225 free(hashed_iface);
226 return EIO;
227 }
228
229 hash_table_insert(&hashed_service->iface_hash_table,
230 &hashed_iface->link);
231 return EOK;
232}
233
234/** Register broker to a service.
235 *
236 * @param service Service to which the broker belongs.
237 *
238 * @return Zero on success or a value from @ref errno.h.
239 *
240 */
241static errno_t ns_broker_register(hashed_service_t *hashed_service)
242{
243 if (hashed_service->broker_sess != NULL)
244 return EEXIST;
245
246 hashed_service->broker_sess = async_callback_receive(EXCHANGE_SERIALIZE);
247 if (hashed_service->broker_sess == NULL)
248 return EIO;
249
250 return EOK;
251}
252
[40313e4]253/** Register service.
254 *
255 * @param service Service to be registered.
[9b1baac]256 * @param iface Interface to be registered.
[40313e4]257 *
258 * @return Zero on success or a value from @ref errno.h.
259 *
260 */
[9b1baac]261errno_t ns_service_register(service_t service, iface_t iface)
[40313e4]262{
[9b1baac]263 ht_link_t *link = hash_table_find(&service_hash_table, &service);
264
265 if (link) {
266 hashed_service_t *hashed_service =
267 hash_table_get_inst(link, hashed_service_t, link);
268
269 assert(hashed_service->service == service);
270
271 return ns_iface_register(hashed_service, iface);
272 }
[a35b458]273
[9cfbf2f]274 hashed_service_t *hashed_service =
275 (hashed_service_t *) malloc(sizeof(hashed_service_t));
276 if (!hashed_service)
[40313e4]277 return ENOMEM;
[a35b458]278
[9b1baac]279 if (!hash_table_create(&hashed_service->iface_hash_table, 0, 0,
280 &iface_hash_table_ops)) {
281 free(hashed_service);
282 return ENOMEM;
283 }
284
285 hashed_service->broker_sess = NULL;
[9cfbf2f]286 hashed_service->service = service;
[9b1baac]287 errno_t rc = ns_iface_register(hashed_service, iface);
288 if (rc != EOK) {
289 free(hashed_service);
290 return rc;
291 }
[a35b458]292
[9cfbf2f]293 hash_table_insert(&service_hash_table, &hashed_service->link);
[007e6efa]294 return EOK;
[40313e4]295}
296
[9b1baac]297/** Register broker service.
298 *
299 * @param service Broker service to be registered.
300 *
301 * @return Zero on success or a value from @ref errno.h.
302 *
303 */
304errno_t ns_service_register_broker(service_t service)
305{
306 ht_link_t *link = hash_table_find(&service_hash_table, &service);
307
308 if (link) {
309 hashed_service_t *hashed_service =
310 hash_table_get_inst(link, hashed_service_t, link);
311
312 assert(hashed_service->service == service);
313
314 return ns_broker_register(hashed_service);
315 }
316
317 hashed_service_t *hashed_service =
318 (hashed_service_t *) malloc(sizeof(hashed_service_t));
319 if (!hashed_service)
320 return ENOMEM;
321
322 if (!hash_table_create(&hashed_service->iface_hash_table, 0, 0,
323 &iface_hash_table_ops)) {
324 free(hashed_service);
325 return ENOMEM;
326 }
327
328 hashed_service->broker_sess = NULL;
329 hashed_service->service = service;
330 errno_t rc = ns_broker_register(hashed_service);
331 if (rc != EOK) {
332 free(hashed_service);
333 return rc;
334 }
335
336 hash_table_insert(&service_hash_table, &hashed_service->link);
337 return EOK;
338}
339
340/** Add pending connection */
341static errno_t ns_pending_conn_add(service_t service, iface_t iface,
342 ipc_call_t *call)
343{
344 pending_conn_t *pending =
345 (pending_conn_t *) malloc(sizeof(pending_conn_t));
346 if (!pending)
347 return ENOMEM;
348
349 link_initialize(&pending->link);
350 pending->service = service;
351 pending->iface = iface;
352 pending->call = *call;
353
354 list_append(&pending->link, &pending_conn);
355 return EOK;
356}
357
[40313e4]358/** Connect client to service.
359 *
[eed4139]360 * @param service Service to be connected to.
361 * @param iface Interface to be connected to.
362 * @param call Pointer to call structure.
[40313e4]363 *
364 * @return Zero on success or a value from @ref errno.h.
365 *
366 */
[9b1baac]367void ns_service_forward(service_t service, iface_t iface, ipc_call_t *call)
[40313e4]368{
[9cfbf2f]369 sysarg_t flags = IPC_GET_ARG4(*call);
[b7fd2a0]370 errno_t retval;
[a35b458]371
[062d900]372 ht_link_t *link = hash_table_find(&service_hash_table, &service);
[40313e4]373 if (!link) {
[9cfbf2f]374 if (flags & IPC_FLAG_BLOCKING) {
[40313e4]375 /* Blocking connection, add to pending list */
[9b1baac]376 errno_t rc = ns_pending_conn_add(service, iface, call);
377 if (rc == EOK)
378 return;
[a35b458]379
[9b1baac]380 retval = rc;
381 goto out;
382 }
383
384 retval = ENOENT;
385 goto out;
386 }
387
388 hashed_service_t *hashed_service =
389 hash_table_get_inst(link, hashed_service_t, link);
[a35b458]390
[9b1baac]391 link = hash_table_find(&hashed_service->iface_hash_table, &iface);
392 if (!link) {
393 if (hashed_service->broker_sess != NULL) {
394 ns_forward(hashed_service->broker_sess, call, iface);
[40313e4]395 return;
396 }
[a35b458]397
[9b1baac]398 if (flags & IPC_FLAG_BLOCKING) {
399 /* Blocking connection, add to pending list */
400 errno_t rc = ns_pending_conn_add(service, iface, call);
401 if (rc == EOK)
402 return;
403
404 retval = rc;
405 goto out;
406 }
407
[40313e4]408 retval = ENOENT;
409 goto out;
410 }
[a35b458]411
[9b1baac]412 hashed_iface_t *hashed_iface =
413 hash_table_get_inst(link, hashed_iface_t, link);
414
415 ns_forward(hashed_iface->sess, call, iface);
[c638c07]416 return;
[a35b458]417
[40313e4]418out:
[984a9ba]419 async_answer_0(call, retval);
[40313e4]420}
421
422/**
423 * @}
424 */
Note: See TracBrowser for help on using the repository browser.