00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00033 #include <ipc/ipc.h>
00034 #include <adt/hash_table.h>
00035 #include <assert.h>
00036 #include <errno.h>
00037 #include <stdio.h>
00038 #include <malloc.h>
00039 #include "service.h"
00040 #include "ns.h"
00041
00042 #define SERVICE_HASH_TABLE_CHAINS 20
00043
00045 typedef struct {
00046 link_t link;
00047 sysarg_t service;
00048 sysarg_t phone;
00049 sysarg_t in_phone_hash;
00050 } hashed_service_t;
00051
00060 static hash_index_t service_hash(unsigned long key[])
00061 {
00062 assert(key);
00063 return (key[0] % SERVICE_HASH_TABLE_CHAINS);
00064 }
00065
00081 static int service_compare(unsigned long key[], hash_count_t keys, link_t *item)
00082 {
00083 assert(key);
00084 assert(keys <= 3);
00085 assert(item);
00086
00087 hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link);
00088
00089 if (keys == 2)
00090 return ((key[0] == hs->service) && (key[1] == hs->in_phone_hash));
00091 else
00092 return (key[0] == hs->service);
00093 }
00094
00100 static void service_remove(link_t *item)
00101 {
00102 assert(item);
00103 free(hash_table_get_instance(item, hashed_service_t, link));
00104 }
00105
00107 static hash_table_operations_t service_hash_table_ops = {
00108 .hash = service_hash,
00109 .compare = service_compare,
00110 .remove_callback = service_remove
00111 };
00112
00114 static hash_table_t service_hash_table;
00115
00117 typedef struct {
00118 link_t link;
00119 sysarg_t service;
00120 ipc_callid_t callid;
00121 sysarg_t arg2;
00122 sysarg_t arg3;
00123 } pending_conn_t;
00124
00125 static link_t pending_conn;
00126
00127 int service_init(void)
00128 {
00129 if (!hash_table_create(&service_hash_table, SERVICE_HASH_TABLE_CHAINS,
00130 3, &service_hash_table_ops)) {
00131 printf(NAME ": No memory available for services\n");
00132 return ENOMEM;
00133 }
00134
00135 list_initialize(&pending_conn);
00136
00137 return EOK;
00138 }
00139
00141 void process_pending_conn(void)
00142 {
00143 link_t *cur;
00144
00145 loop:
00146 for (cur = pending_conn.next; cur != &pending_conn; cur = cur->next) {
00147 pending_conn_t *pr = list_get_instance(cur, pending_conn_t, link);
00148
00149 unsigned long keys[3] = {
00150 pr->service,
00151 0,
00152 0
00153 };
00154
00155 link_t *link = hash_table_find(&service_hash_table, keys);
00156 if (!link)
00157 continue;
00158
00159 hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
00160 (void) ipc_forward_fast(pr->callid, hs->phone, pr->arg2,
00161 pr->arg3, 0, IPC_FF_NONE);
00162
00163 list_remove(cur);
00164 free(pr);
00165 goto loop;
00166 }
00167 }
00168
00178 int register_service(sysarg_t service, sysarg_t phone, ipc_call_t *call)
00179 {
00180 unsigned long keys[3] = {
00181 service,
00182 call->in_phone_hash,
00183 0
00184 };
00185
00186 if (hash_table_find(&service_hash_table, keys))
00187 return EEXISTS;
00188
00189 hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t));
00190 if (!hs)
00191 return ENOMEM;
00192
00193 link_initialize(&hs->link);
00194 hs->service = service;
00195 hs->phone = phone;
00196 hs->in_phone_hash = call->in_phone_hash;
00197 hash_table_insert(&service_hash_table, keys, &hs->link);
00198
00199 return EOK;
00200 }
00201
00211 void connect_to_service(sysarg_t service, ipc_call_t *call, ipc_callid_t callid)
00212 {
00213 sysarg_t retval;
00214 unsigned long keys[3] = {
00215 service,
00216 0,
00217 0
00218 };
00219
00220 link_t *link = hash_table_find(&service_hash_table, keys);
00221 if (!link) {
00222 if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) {
00223
00224 pending_conn_t *pr =
00225 (pending_conn_t *) malloc(sizeof(pending_conn_t));
00226 if (!pr) {
00227 retval = ENOMEM;
00228 goto out;
00229 }
00230
00231 link_initialize(&pr->link);
00232 pr->service = service;
00233 pr->callid = callid;
00234 pr->arg2 = IPC_GET_ARG2(*call);
00235 pr->arg3 = IPC_GET_ARG3(*call);
00236 list_append(&pr->link, &pending_conn);
00237 return;
00238 }
00239 retval = ENOENT;
00240 goto out;
00241 }
00242
00243 hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
00244 (void) ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call),
00245 IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
00246 return;
00247
00248 out:
00249 if (!(callid & IPC_CALLID_NOTIFICATION))
00250 ipc_answer_0(callid, retval);
00251 }
00252