Subversion Repositories HelenOS

Rev

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

  1. /*
  2.  * Copyright (c) 2008 Jiri Svoboda
  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 trace
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <libadt/hash_table.h>
  38.  
  39. #include "ipc_desc.h"
  40. #include "proto.h"
  41. #include "ipcp.h"
  42.  
  43. #define IPCP_CALLID_SYNC 0
  44.  
  45. typedef struct {
  46.     int phone_hash;
  47.     ipc_call_t question;
  48.  
  49.     int call_hash;
  50.  
  51.     link_t link;
  52. } pending_call_t;
  53.  
  54. typedef struct {
  55.     int server;
  56.     proto_t *proto;
  57. } connection_t;
  58.  
  59. #define MAX_PHONE 64
  60. connection_t connections[MAX_PHONE];
  61. int have_conn[MAX_PHONE];
  62.  
  63. #define PCALL_TABLE_CHAINS 32
  64. hash_table_t pending_calls;
  65.  
  66. /*
  67.  * Pseudo-protocols
  68.  */
  69. proto_t *proto_system;      /**< Protocol describing system IPC methods. */
  70. proto_t *proto_unknown;     /**< Protocol with no known methods. */
  71.  
  72. static hash_index_t pending_call_hash(unsigned long key[]);
  73. static int pending_call_compare(unsigned long key[], hash_count_t keys,
  74.     link_t *item);
  75. static void pending_call_remove_callback(link_t *item);
  76.  
  77. hash_table_operations_t pending_call_ops = {
  78.     .hash = pending_call_hash,
  79.     .compare = pending_call_compare,
  80.     .remove_callback = pending_call_remove_callback
  81. };
  82.  
  83.  
  84. static hash_index_t pending_call_hash(unsigned long key[])
  85. {
  86. //  printf("pending_call_hash\n");
  87.     return key[0] % PCALL_TABLE_CHAINS;
  88. }
  89.  
  90. static int pending_call_compare(unsigned long key[], hash_count_t keys,
  91.     link_t *item)
  92. {
  93.     pending_call_t *hs;
  94.  
  95. //  printf("pending_call_compare\n");
  96.     hs = hash_table_get_instance(item, pending_call_t, link);
  97.  
  98.     return key[0] == hs->call_hash;
  99. }
  100.  
  101. static void pending_call_remove_callback(link_t *item)
  102. {
  103. //  printf("pending_call_remove_callback\n");
  104. }
  105.  
  106.  
  107. void ipcp_connection_set(int phone, int server, proto_t *proto)
  108. {
  109.     if (phone <0 || phone >= MAX_PHONE) return;
  110.     connections[phone].server = server;
  111.     connections[phone].proto = proto;
  112.     have_conn[phone] = 1;
  113. }
  114.  
  115. void ipcp_connection_clear(int phone)
  116. {
  117.     have_conn[phone] = 0;
  118.     connections[phone].server = 0;
  119.     connections[phone].proto = NULL;
  120. }
  121.  
  122. static void ipc_m_print(proto_t *proto, ipcarg_t method)
  123. {
  124.     oper_t *oper;
  125.  
  126.     /* Try system methods first */
  127.     oper = proto_get_oper(proto_system, method);
  128.  
  129.     if (oper == NULL && proto != NULL) {
  130.         /* Not a system method, try the user protocol. */
  131.         oper = proto_get_oper(proto, method);
  132.     }
  133.  
  134.     if (oper != NULL) {
  135.         printf("%s (%d)", oper->name, method);
  136.         return;
  137.     }
  138.  
  139.     printf("%d", method);
  140. }
  141.  
  142. void ipcp_init(void)
  143. {
  144.     ipc_m_desc_t *desc;
  145.     oper_t *oper;
  146.  
  147.     /*
  148.      * Create a pseudo-protocol 'unknown' that has no known methods.
  149.      */
  150.     proto_unknown = proto_new("unknown");
  151.  
  152.     /*
  153.      * Create a pseudo-protocol 'system' defining names of system IPC
  154.      * methods.
  155.      */
  156.     proto_system = proto_new("system");
  157.  
  158.     desc = ipc_methods;
  159.     while (desc->number != 0) {
  160.         oper = oper_new(desc->name);
  161.         proto_add_oper(proto_system, desc->number, oper);
  162.  
  163.         ++desc;
  164.     }
  165.  
  166.     hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
  167. }
  168.  
  169. void ipcp_cleanup(void)
  170. {
  171.     proto_delete(proto_system);
  172.     hash_table_destroy(&pending_calls);
  173. }
  174.  
  175. void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
  176. {
  177.     pending_call_t *pcall;
  178.     proto_t *proto;
  179.     unsigned long key[1];
  180.  
  181.     if (have_conn[phone]) proto = connections[phone].proto;
  182.     else proto = NULL;
  183.  
  184. //  printf("ipcp_call_out()\n");
  185.     printf("call id: 0x%x, phone: %d, proto: %s, method: ", hash, phone,
  186.         (proto ? proto->name : "n/a"));
  187.     ipc_m_print(proto, IPC_GET_METHOD(*call));
  188.     printf(" args: (%u, %u, %u, %u, %u)\n",
  189.         IPC_GET_ARG1(*call),
  190.         IPC_GET_ARG2(*call),
  191.         IPC_GET_ARG3(*call),
  192.         IPC_GET_ARG4(*call),
  193.         IPC_GET_ARG5(*call)
  194.     );
  195.  
  196.     /* Store call in hash table for response matching */
  197.  
  198.     pcall = malloc(sizeof(pending_call_t));
  199.     pcall->phone_hash = phone;
  200.     pcall->question = *call;
  201.     pcall->call_hash = hash;
  202.  
  203.     key[0] = hash;
  204.  
  205.     hash_table_insert(&pending_calls, key, &pcall->link);
  206. }
  207.  
  208. static void parse_answer(pending_call_t *pcall, ipc_call_t *answer)
  209. {
  210.     int phone;
  211.     ipcarg_t method;
  212.     ipcarg_t service;
  213.     int retval;
  214.     proto_t *proto;
  215.     int cphone;
  216.  
  217. //  printf("parse_answer\n");
  218.  
  219.     phone = pcall->phone_hash;
  220.     method = IPC_GET_METHOD(pcall->question);
  221.     retval = IPC_GET_RETVAL(*answer);
  222.     printf("phone=%d, method=%d, retval=%d\n",
  223.         phone, method, retval);
  224.  
  225.     if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
  226.         /* Connected to a service (through NS) */
  227.         service = IPC_GET_ARG1(pcall->question);
  228.         proto = proto_get_by_srv(service);
  229.         if (proto == NULL) proto = proto_unknown;
  230.  
  231.         cphone = IPC_GET_ARG5(*answer);
  232.         printf("registering connection (phone %d, protocol: %s)\n", cphone,
  233.             proto->name);
  234.         ipcp_connection_set(cphone, 0, proto);
  235.     }
  236. }
  237.  
  238. void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
  239. {
  240.     link_t *item;
  241.     pending_call_t *pcall;
  242.     unsigned long key[1];
  243.  
  244. //  printf("ipcp_call_in()\n");
  245. /*  printf("phone: %d, method: ", call->in_phone_hash);
  246.     ipc_m_print(IPC_GET_METHOD(*call));
  247.     printf(" args: (%u, %u, %u, %u, %u)\n",
  248.         IPC_GET_ARG1(*call),
  249.         IPC_GET_ARG2(*call),
  250.         IPC_GET_ARG3(*call),
  251.         IPC_GET_ARG4(*call),
  252.         IPC_GET_ARG5(*call)
  253.     );*/
  254.  
  255.     if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
  256.         /* Not a response */
  257.         printf("Not a response (hash %d)\n", hash);
  258.         return;
  259.     }
  260.  
  261.     hash = hash & ~IPC_CALLID_ANSWERED;
  262.     key[0] = hash;
  263.  
  264.     item = hash_table_find(&pending_calls, key);
  265.     if (item == NULL) return; // No matching question found
  266.    
  267.     pcall = hash_table_get_instance(item, pending_call_t, link);
  268.  
  269.     printf("response matched to question\n");
  270.     hash_table_remove(&pending_calls, key, 1);
  271.  
  272.     parse_answer(pcall, call);
  273.     free(pcall);
  274. }
  275.  
  276. void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
  277. {
  278.     ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
  279.     ipcp_call_in(answer, IPCP_CALLID_SYNC);
  280. }
  281.  
  282. void ipcp_hangup(int phone, int rc)
  283. {
  284.     printf("hangup phone %d -> %d\n", phone, rc);
  285.     ipcp_connection_clear(phone);
  286. }
  287.  
  288. /** @}
  289.  */
  290.