45,15 → 45,19 |
|
#define NS_HASH_TABLE_CHAINS 20 |
|
static int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call); |
static int connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid); |
|
/* Static functions implementing NS hash table operations. */ |
static hash_index_t ns_hash(unsigned long *key); |
static int ns_compare(unsigned long *key, hash_count_t keys, link_t *item); |
static void ns_remove(link_t *item); |
|
/** Operations for NS hash table. */ |
static hash_table_operations_t ns_hash_table_ops = { |
.hash = ns_hash, |
.compare = ns_compare, |
.remove_callback = NULL |
.remove_callback = ns_remove |
}; |
|
/** NS hash table structure. */ |
64,6 → 68,7 |
link_t link; |
ipcarg_t service; /**< Number of the service. */ |
ipcarg_t phone; /**< Phone registered with the service. */ |
ipcarg_t in_phone_hash; /**< Incoming phone hash. */ |
} hashed_service_t; |
|
/* |
100,7 → 105,7 |
|
printf("%s: Name service started.\n", NAME); |
|
if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 1, &ns_hash_table_ops)) { |
if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 3, &ns_hash_table_ops)) { |
printf("%s: cannot create hash table\n", NAME); |
return ENOMEM; |
} |
110,7 → 115,7 |
// ipc_register_irq(1, &i8042_kbd); |
while (1) { |
callid = ipc_wait_for_call(&call, 0); |
printf("NS: Call phone=%lX...", call.phoneid); |
printf("NS: Call in_phone_hash=%lX...", call.in_phone_hash); |
switch (IPC_GET_METHOD(call)) { |
case IPC_M_AS_SEND: |
as = (char *)IPC_GET_ARG2(call); |
130,35 → 135,18 |
printf("Phone hung up.\n"); |
retval = 0; |
break; |
case IPC_M_CONNECT_TO_ME:; |
case IPC_M_CONNECT_TO_ME: |
/* |
* Request for registration of a service. |
* Server requests service registration. |
*/ |
ipcarg_t service; |
ipcarg_t phone; |
hashed_service_t *hs; |
|
service = IPC_GET_ARG1(call); |
phone = IPC_GET_ARG3(call); |
printf("Registering service %d on phone %d...", service, phone); |
|
hs = (hashed_service_t *) malloc(sizeof(hashed_service_t)); |
if (!hs) { |
printf("Failed to register service %d.\n", service); |
} |
|
link_initialize(&hs->link); |
hs->service = service; |
hs->phone = phone; |
hash_table_insert(&ns_hash_table, (unsigned long *) &service, &hs->link); |
|
ping_phone = phone; |
retval = 0; |
retval = register_service(IPC_GET_ARG1(call), IPC_GET_ARG3(call), &call); |
ping_phone = IPC_GET_ARG3(call); |
break; |
case IPC_M_CONNECT_ME_TO: |
printf("Connectme(%P)to: %zd\n", |
IPC_GET_ARG3(call), IPC_GET_ARG1(call)); |
retval = 0; |
/* |
* Client requests to be connected to a service. |
*/ |
retval = connect_to_service(IPC_GET_ARG1(call), &call, callid); |
break; |
case NS_PING: |
printf("Ping...%P %P\n", IPC_GET_ARG1(call), |
188,10 → 176,70 |
} |
} |
|
/** Register server. |
* |
* @param service Service to be registered. |
* @param phone phone Phone to be used for connections to the service. |
* @param call Pointer to call structure. |
* |
* @return Zero on success or a value from @ref errno.h. |
*/ |
int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call) |
{ |
unsigned long keys[3] = { service, call->in_phone_hash, 0 }; |
hashed_service_t *hs; |
|
printf("Registering service %d on phone %d...", service, phone); |
|
if (hash_table_find(&ns_hash_table, keys)) { |
printf("Service %d already registered.\n", service); |
return EEXISTS; |
} |
|
hs = (hashed_service_t *) malloc(sizeof(hashed_service_t)); |
if (!hs) { |
printf("Failed to register service %d.\n", service); |
return ENOMEM; |
} |
|
link_initialize(&hs->link); |
hs->service = service; |
hs->phone = phone; |
hs->in_phone_hash = call->in_phone_hash; |
hash_table_insert(&ns_hash_table, keys, &hs->link); |
|
return 0; |
} |
|
/** Connect client to service. |
* |
* @param service Service to be connected to. |
* @param call Pointer to call structure. |
* @param callid Call ID of the request. |
* |
* @return Zero on success or a value from @ref errno.h. |
*/ |
int connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid) |
{ |
unsigned long keys[3] = { service, 0, 0 }; |
link_t *hlp; |
hashed_service_t *hs; |
|
hlp = hash_table_find(&ns_hash_table, keys); |
if (!hlp) { |
printf("Service %d noty registered.\n", service); |
return ENOENT; |
} |
hs = hash_table_get_instance(hlp, hashed_service_t, link); |
printf("Connecting in_phone_hash=%lX to service at phone %d...", call->in_phone_hash, hs->phone); |
return ipc_forward_fast(callid, hs->phone, 0, 0); |
} |
|
/** Compute hash index into NS hash table. |
* |
* @param key Pointer to single key (i.e. service number). |
* @return Hash index corresponding to *key. |
* @param key Pointer keys. However, only the first key (i.e. service number) |
* is used to compute the hash index. |
* @return Hash index corresponding to key[0]. |
*/ |
hash_index_t ns_hash(unsigned long *key) |
{ |
201,20 → 249,39 |
|
/** Compare a key with hashed item. |
* |
* @param key Single key pointer. |
* @param keys Must be 1. |
* This compare function always ignores the third key. |
* It exists only to make it possible to remove records |
* originating from connection with key[1] in_phone_hash |
* value. Note that this is close to being classified |
* as a nasty hack. |
* |
* @param key Array of keys. |
* @param keys Must be lesser or equal to 3. |
* @param item Pointer to a hash table item. |
* @return Non-zero if the key matches the item, zero otherwise. |
*/ |
int ns_compare(unsigned long *key, hash_count_t keys, link_t *item) |
int ns_compare(unsigned long key[], hash_count_t keys, link_t *item) |
{ |
hashed_service_t *hs; |
|
assert(key); |
assert(keys == 1); |
assert(keys <= 3); |
assert(item); |
|
hs = hash_table_get_instance(item, hashed_service_t, link); |
|
return *key == hs->service; |
if (keys == 2) |
return key[1] == hs->in_phone_hash; |
else |
return key[0] == hs->service; |
} |
|
/** Perform actions after removal of item from the hash table. |
* |
* @param item Item that was removed from the hash table. |
*/ |
void ns_remove(link_t *item) |
{ |
assert(item); |
free(hash_table_get_instance(item, hashed_service_t, link)); |
} |