service.c

00001 /*
00002  * Copyright (c) 2009 Martin Decky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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                         /* Blocking connection, add to pending list */
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 

Generated on Thu Jun 2 07:45:50 2011 for HelenOS/USB by  doxygen 1.4.7