Subversion Repositories HelenOS

Rev

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