2
* Copyright (c) 2009 Martin Decky
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
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.
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.
34
#include <adt/hash_table.h>
40
#define SERVICE_HASH_TABLE_CHAINS 20
42
/** Service hash table item. */
45
ipcarg_t service; /**< Number of the service. */
46
ipcarg_t phone; /**< Phone registered with the service. */
47
ipcarg_t in_phone_hash; /**< Incoming phone hash. */
50
/** Compute hash index into service hash table.
52
* @param key Pointer keys. However, only the first key (i.e. service number)
53
* is used to compute the hash index.
55
* @return Hash index corresponding to key[0].
58
static hash_index_t service_hash(unsigned long *key)
61
return (*key % SERVICE_HASH_TABLE_CHAINS);
64
/** Compare a key with hashed item.
66
* This compare function always ignores the third key.
67
* It exists only to make it possible to remove records
68
* originating from connection with key[1] in_phone_hash
69
* value. Note that this is close to being classified
72
* @param key Array of keys.
73
* @param keys Must be lesser or equal to 3.
74
* @param item Pointer to a hash table item.
76
* @return Non-zero if the key matches the item, zero otherwise.
79
static int service_compare(unsigned long key[], hash_count_t keys, link_t *item)
85
hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link);
88
return (key[1] == hs->in_phone_hash);
90
return (key[0] == hs->service);
93
/** Perform actions after removal of item from the hash table.
95
* @param item Item that was removed from the hash table.
98
static void service_remove(link_t *item)
101
free(hash_table_get_instance(item, hashed_service_t, link));
104
/** Operations for service hash table. */
105
static hash_table_operations_t service_hash_table_ops = {
106
.hash = service_hash,
107
.compare = service_compare,
108
.remove_callback = service_remove
111
/** Service hash table structure. */
112
static hash_table_t service_hash_table;
114
/** Pending connection structure. */
117
ipcarg_t service; /**< Number of the service. */
118
ipc_callid_t callid; /**< Call ID waiting for the connection */
119
ipcarg_t arg2; /**< Second argument */
120
ipcarg_t arg3; /**< Third argument */
123
static link_t pending_conn;
125
int service_init(void)
127
if (!hash_table_create(&service_hash_table, SERVICE_HASH_TABLE_CHAINS,
128
3, &service_hash_table_ops)) {
129
printf(NAME ": No memory available for services\n");
133
list_initialize(&pending_conn);
138
/** Process pending connection requests */
139
void process_pending_conn(void)
144
for (cur = pending_conn.next; cur != &pending_conn; cur = cur->next) {
145
pending_conn_t *pr = list_get_instance(cur, pending_conn_t, link);
147
unsigned long keys[3] = {
153
link_t *link = hash_table_find(&service_hash_table, keys);
157
hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
158
ipcarg_t retval = ipc_forward_fast(pr->callid, hs->phone,
159
pr->arg2, pr->arg3, 0, IPC_FF_NONE);
161
if (!(pr->callid & IPC_CALLID_NOTIFICATION))
162
ipc_answer_0(pr->callid, retval);
170
/** Register service.
172
* @param service Service to be registered.
173
* @param phone Phone to be used for connections to the service.
174
* @param call Pointer to call structure.
176
* @return Zero on success or a value from @ref errno.h.
179
int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call)
181
unsigned long keys[3] = {
187
if (hash_table_find(&service_hash_table, keys))
190
hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t));
194
link_initialize(&hs->link);
195
hs->service = service;
197
hs->in_phone_hash = call->in_phone_hash;
198
hash_table_insert(&service_hash_table, keys, &hs->link);
203
/** Connect client to service.
205
* @param service Service to be connected to.
206
* @param call Pointer to call structure.
207
* @param callid Call ID of the request.
209
* @return Zero on success or a value from @ref errno.h.
212
void connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid)
215
unsigned long keys[3] = {
221
link_t *link = hash_table_find(&service_hash_table, keys);
223
if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) {
224
/* Blocking connection, add to pending list */
226
(pending_conn_t *) malloc(sizeof(pending_conn_t));
232
pr->service = service;
234
pr->arg2 = IPC_GET_ARG2(*call);
235
pr->arg3 = IPC_GET_ARG3(*call);
236
list_append(&pr->link, &pending_conn);
243
hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
244
retval = ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call),
245
IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
248
if (!(callid & IPC_CALLID_NOTIFICATION))
249
ipc_answer_0(callid, retval);