Subversion Repositories HelenOS

Rev

Rev 4509 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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 <ipc/ipc.h>
  34. #include <libadt/hash_table.h>
  35. #include <assert.h>
  36. #include <errno.h>
  37. #include "service.h"
  38. #include "ns.h"
  39.  
  40. #define SERVICE_HASH_TABLE_CHAINS  20
  41.  
  42. /** Service hash table item. */
  43. typedef struct {
  44.     link_t link;
  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. */
  48. } hashed_service_t;
  49.  
  50. /** Compute hash index into service hash table.
  51.  *
  52.  * @param key Pointer keys. However, only the first key (i.e. service number)
  53.  *            is used to compute the hash index.
  54.  *
  55.  * @return Hash index corresponding to key[0].
  56.  *
  57.  */
  58. static hash_index_t service_hash(unsigned long *key)
  59. {
  60.     assert(key);
  61.     return (*key % SERVICE_HASH_TABLE_CHAINS);
  62. }
  63.  
  64. /** Compare a key with hashed item.
  65.  *
  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
  70.  * as a nasty hack.
  71.  *
  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.
  75.  *
  76.  * @return Non-zero if the key matches the item, zero otherwise.
  77.  *
  78.  */
  79. static int service_compare(unsigned long key[], hash_count_t keys, link_t *item)
  80. {
  81.     assert(key);
  82.     assert(keys <= 3);
  83.     assert(item);
  84.    
  85.     hashed_service_t *hs = hash_table_get_instance(item, hashed_service_t, link);
  86.    
  87.     if (keys == 2)
  88.         return (key[1] == hs->in_phone_hash);
  89.     else
  90.         return (key[0] == hs->service);
  91. }
  92.  
  93. /** Perform actions after removal of item from the hash table.
  94.  *
  95.  * @param item Item that was removed from the hash table.
  96.  *
  97.  */
  98. static void service_remove(link_t *item)
  99. {
  100.     assert(item);
  101.     free(hash_table_get_instance(item, hashed_service_t, link));
  102. }
  103.  
  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
  109. };
  110.  
  111. /** Service hash table structure. */
  112. static hash_table_t service_hash_table;
  113.  
  114. /** Pending connection structure. */
  115. typedef struct {
  116.     link_t link;
  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 */
  121. } pending_conn_t;
  122.  
  123. static link_t pending_conn;
  124.  
  125. int service_init(void)
  126. {
  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");
  130.         return ENOMEM;
  131.     }
  132.    
  133.     list_initialize(&pending_conn);
  134.    
  135.     return EOK;
  136. }
  137.  
  138. /** Process pending connection requests */
  139. void process_pending_conn(void)
  140. {
  141.     link_t *cur;
  142.    
  143. loop:
  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);
  146.        
  147.         unsigned long keys[3] = {
  148.             pr->service,
  149.             0,
  150.             0
  151.         };
  152.        
  153.         link_t *link = hash_table_find(&service_hash_table, keys);
  154.         if (!link)
  155.             continue;
  156.        
  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);
  160.        
  161.         if (!(pr->callid & IPC_CALLID_NOTIFICATION))
  162.             ipc_answer_0(pr->callid, retval);
  163.        
  164.         list_remove(cur);
  165.         free(pr);
  166.         goto loop;
  167.     }
  168. }
  169.  
  170. /** Register service.
  171.  *
  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.
  175.  *
  176.  * @return Zero on success or a value from @ref errno.h.
  177.  *
  178.  */
  179. int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call)
  180. {
  181.     unsigned long keys[3] = {
  182.         service,
  183.         call->in_phone_hash,
  184.         0
  185.     };
  186.    
  187.     if (hash_table_find(&service_hash_table, keys))
  188.         return EEXISTS;
  189.    
  190.     hashed_service_t *hs = (hashed_service_t *) malloc(sizeof(hashed_service_t));
  191.     if (!hs)
  192.         return ENOMEM;
  193.    
  194.     link_initialize(&hs->link);
  195.     hs->service = service;
  196.     hs->phone = phone;
  197.     hs->in_phone_hash = call->in_phone_hash;
  198.     hash_table_insert(&service_hash_table, keys, &hs->link);
  199.    
  200.     return 0;
  201. }
  202.  
  203. /** Connect client to service.
  204.  *
  205.  * @param service Service to be connected to.
  206.  * @param call    Pointer to call structure.
  207.  * @param callid  Call ID of the request.
  208.  *
  209.  * @return Zero on success or a value from @ref errno.h.
  210.  *
  211.  */
  212. void connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid)
  213. {
  214.     ipcarg_t retval;
  215.     unsigned long keys[3] = {
  216.         service,
  217.         0,
  218.         0
  219.     };
  220.    
  221.     link_t *link = hash_table_find(&service_hash_table, keys);
  222.     if (!link) {
  223.         if (IPC_GET_ARG4(*call) & IPC_FLAG_BLOCKING) {
  224.             /* Blocking connection, add to pending list */
  225.             pending_conn_t *pr =
  226.                 (pending_conn_t *) malloc(sizeof(pending_conn_t));
  227.             if (!pr) {
  228.                 retval = ENOMEM;
  229.                 goto out;
  230.             }
  231.            
  232.             pr->service = service;
  233.             pr->callid = callid;
  234.             pr->arg2 = IPC_GET_ARG2(*call);
  235.             pr->arg3 = IPC_GET_ARG3(*call);
  236.             list_append(&pr->link, &pending_conn);
  237.             return;
  238.         }
  239.         retval = ENOENT;
  240.         goto out;
  241.     }
  242.    
  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);
  246.    
  247. out:
  248.     if (!(callid & IPC_CALLID_NOTIFICATION))
  249.         ipc_answer_0(callid, retval);
  250. }
  251.  
  252. /**
  253.  * @}
  254.  */
  255.