Subversion Repositories HelenOS

Rev

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