source: mainline/uspace/srv/ns/service.c@ 95658c9

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 95658c9 was 5e801dc, checked in by GitHub <noreply@…>, 6 years ago

Indicate and enforce constness of hash table key in certain functions (#158)

The assumption here is that modifying key in the hash/equal functions in something completely unexpected, and not something you would ever want to do intentionally, so it makes sense to disallow it entirely to get that extra level of checking.

  • Property mode set to 100644
File size: 10.1 KB
Line 
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
33#include <adt/hash_table.h>
34#include <assert.h>
35#include <async.h>
36#include <errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include "service.h"
40#include "ns.h"
41
42/** Service hash table item. */
43typedef struct {
44 ht_link_t link;
45
46 /** Service ID */
47 service_t service;
48
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
63 /** Session to the service */
64 async_sess_t *sess;
65} hashed_iface_t;
66
67static size_t service_key_hash(const void *key)
68{
69 const service_t *srv = key;
70 return *srv;
71}
72
73static size_t service_hash(const ht_link_t *item)
74{
75 hashed_service_t *service =
76 hash_table_get_inst(item, hashed_service_t, link);
77
78 return service->service;
79}
80
81static bool service_key_equal(const void *key, const ht_link_t *item)
82{
83 const service_t *srv = key;
84 hashed_service_t *service =
85 hash_table_get_inst(item, hashed_service_t, link);
86
87 return service->service == *srv;
88}
89
90static size_t iface_key_hash(const void *key)
91{
92 const iface_t *iface = key;
93 return *iface;
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
104static bool iface_key_equal(const void *key, const ht_link_t *item)
105{
106 const iface_t *kiface = key;
107 hashed_iface_t *iface =
108 hash_table_get_inst(item, hashed_iface_t, link);
109
110 return iface->iface == *kiface;
111}
112
113/** Operations for service hash table. */
114static hash_table_ops_t service_hash_table_ops = {
115 .hash = service_hash,
116 .key_hash = service_key_hash,
117 .key_equal = service_key_equal,
118 .equal = NULL,
119 .remove_callback = NULL
120};
121
122/** Operations for interface hash table. */
123static hash_table_ops_t iface_hash_table_ops = {
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
131/** Service hash table structure. */
132static hash_table_t service_hash_table;
133
134/** Pending connection structure. */
135typedef struct {
136 link_t link;
137 service_t service; /**< Service ID */
138 iface_t iface; /**< Interface ID */
139 ipc_call_t call; /**< Call waiting for the connection */
140} pending_conn_t;
141
142static list_t pending_conn;
143
144errno_t ns_service_init(void)
145{
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);
149 return ENOMEM;
150 }
151
152 list_initialize(&pending_conn);
153
154 return EOK;
155}
156
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);
160 async_forward_1(call, exch, iface, ipc_get_arg3(call), IPC_FF_NONE);
161 async_exchange_end(exch);
162}
163
164/** Process pending connection requests */
165void ns_pending_conn_process(void)
166{
167loop:
168 list_foreach(pending_conn, link, pending_conn_t, pending) {
169 ht_link_t *link =
170 hash_table_find(&service_hash_table, &pending->service);
171 if (!link)
172 continue;
173
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);
197
198 list_remove(&pending->link);
199 free(pending);
200
201 goto loop;
202 }
203}
204
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
256/** Register service.
257 *
258 * @param service Service to be registered.
259 * @param iface Interface to be registered.
260 *
261 * @return Zero on success or a value from @ref errno.h.
262 *
263 */
264errno_t ns_service_register(service_t service, iface_t iface)
265{
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 }
276
277 hashed_service_t *hashed_service =
278 (hashed_service_t *) malloc(sizeof(hashed_service_t));
279 if (!hashed_service)
280 return ENOMEM;
281
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;
289 hashed_service->service = service;
290 errno_t rc = ns_iface_register(hashed_service, iface);
291 if (rc != EOK) {
292 free(hashed_service);
293 return rc;
294 }
295
296 hash_table_insert(&service_hash_table, &hashed_service->link);
297 return EOK;
298}
299
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
361/** Connect client to service.
362 *
363 * @param service Service to be connected to.
364 * @param iface Interface to be connected to.
365 * @param call Pointer to call structure.
366 *
367 * @return Zero on success or a value from @ref errno.h.
368 *
369 */
370void ns_service_forward(service_t service, iface_t iface, ipc_call_t *call)
371{
372 sysarg_t flags = ipc_get_arg4(call);
373 errno_t retval;
374
375 ht_link_t *link = hash_table_find(&service_hash_table, &service);
376 if (!link) {
377 if (flags & IPC_FLAG_BLOCKING) {
378 /* Blocking connection, add to pending list */
379 errno_t rc = ns_pending_conn_add(service, iface, call);
380 if (rc == EOK)
381 return;
382
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);
393
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);
398 return;
399 }
400
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
411 retval = ENOENT;
412 goto out;
413 }
414
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);
419 return;
420
421out:
422 async_answer_0(call, retval);
423}
424
425/**
426 * @}
427 */
Note: See TracBrowser for help on using the repository browser.