Subversion Repositories HelenOS

Rev

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

  1. /** @addtogroup sctrace
  2.  * @{
  3.  */
  4. /** @file
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <libadt/hash_table.h>
  10.  
  11. #include "ipc_desc.h"
  12. #include "proto.h"
  13. #include "ipcp.h"
  14.  
  15. #define IPCP_CALLID_SYNC 0
  16.  
  17. typedef struct {
  18.     int phone_hash;
  19.     ipc_call_t question;
  20.  
  21.     int call_hash;
  22.  
  23.     link_t link;
  24. } pending_call_t;
  25.  
  26. typedef struct {
  27.     int server;
  28.     proto_t *proto;
  29. } connection_t;
  30.  
  31. #define MAX_PHONE 64
  32. connection_t connections[MAX_PHONE];
  33. int have_conn[MAX_PHONE];
  34.  
  35. #define PCALL_TABLE_CHAINS 32
  36. hash_table_t pending_calls;
  37.  
  38. hash_index_t pending_call_hash(unsigned long key[])
  39. {
  40. //  printf("pending_call_hash\n");
  41.     return key[0] % PCALL_TABLE_CHAINS;
  42. }
  43.  
  44. int pending_call_compare(unsigned long key[], hash_count_t keys,
  45.     link_t *item)
  46. {
  47.     pending_call_t *hs;
  48.  
  49. //  printf("pending_call_compare\n");
  50.     hs = hash_table_get_instance(item, pending_call_t, link);
  51.  
  52.     return key[0] == hs->call_hash;
  53. }
  54.  
  55. void pending_call_remove_callback(link_t *item)
  56. {
  57. //  printf("pending_call_remove_callback\n");
  58. }
  59.  
  60. hash_table_operations_t pending_call_ops = {
  61.     .hash = pending_call_hash,
  62.     .compare = pending_call_compare,
  63.     .remove_callback = pending_call_remove_callback
  64. };
  65.  
  66. static void connection_set(int phone, int server, proto_t *proto)
  67. {
  68.     if (phone <0 || phone >= MAX_PHONE) return;
  69.     connections[phone].server = server;
  70.     connections[phone].proto = proto;
  71.     have_conn[phone] = 1;
  72. }
  73.  
  74. static void connection_clear(int phone)
  75. {
  76.     have_conn[phone] = 0;
  77.     connections[phone].server = 0;
  78.     connections[phone].proto = NULL;
  79. }
  80.  
  81. static void ipc_m_print(proto_t *proto, ipcarg_t method)
  82. {
  83.     ipc_m_desc_t *desc;
  84.     oper_t *oper;
  85.  
  86.     /* FIXME: too slow */
  87.     desc = ipc_methods;
  88.     while (desc->number != 0) {
  89.         if (desc->number == method) {
  90.             printf("%s (%d)", desc->name, method);
  91.             return;
  92.         }
  93.  
  94.         ++desc;
  95.     }
  96.  
  97.     if (proto != NULL) {
  98.         oper = proto_get_oper(proto, method);
  99.         if (oper != NULL) {
  100.             printf("%s (%d)", oper->name, method);
  101.             return;
  102.         }
  103.     }
  104.  
  105.     printf("%d", method);
  106. }
  107.  
  108. void ipcp_init(void)
  109. {
  110.     hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
  111. }
  112.  
  113. void ipcp_cleanup(void)
  114. {
  115.     hash_table_destroy(&pending_calls);
  116. }
  117.  
  118. void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
  119. {
  120.     pending_call_t *pcall;
  121.     proto_t *proto;
  122.  
  123.     if (have_conn[phone]) proto = connections[phone].proto;
  124.     else proto = NULL;
  125.  
  126. //  printf("ipcp_call_out()\n");
  127.     printf("call id: 0x%x, phone: %d, proto: %s, method: ", hash, phone,
  128.         (proto ? proto->name : "n/a"));
  129.     ipc_m_print(proto, IPC_GET_METHOD(*call));
  130.     printf(" args: (%u, %u, %u, %u, %u)\n",
  131.         IPC_GET_ARG1(*call),
  132.         IPC_GET_ARG2(*call),
  133.         IPC_GET_ARG3(*call),
  134.         IPC_GET_ARG4(*call),
  135.         IPC_GET_ARG5(*call)
  136.     );
  137.  
  138.     /* Store call in hash table for response matching */
  139.  
  140.     pcall = malloc(sizeof(pending_call_t));
  141.     pcall->phone_hash = phone;
  142.     pcall->question = *call;
  143.     pcall->call_hash = hash;
  144.  
  145.     hash_table_insert(&pending_calls, &pcall->call_hash, &pcall->link);
  146. }
  147.  
  148. static void parse_answer(pending_call_t *pcall, ipc_call_t *answer)
  149. {
  150.     int phone;
  151.     ipcarg_t method;
  152.     ipcarg_t service;
  153.     int retval;
  154.     static proto_t proto_unknown = { .name = "unknown" };
  155.     proto_t *proto;
  156.     int cphone;
  157.  
  158. //  printf("parse_answer\n");
  159.  
  160.     phone = pcall->phone_hash;
  161.     method = IPC_GET_METHOD(pcall->question);
  162.     retval = IPC_GET_RETVAL(*answer);
  163.     printf("phone=%d, method=%d, retval=%d\n",
  164.         phone, method, retval);
  165.  
  166.     if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
  167.         /* Connected to a service (through NS) */
  168.         service = IPC_GET_ARG1(pcall->question);
  169.         proto = proto_get_by_srv(service);
  170.         if (proto == NULL) proto = &proto_unknown;
  171.  
  172.         cphone = IPC_GET_ARG5(*answer);
  173.         printf("registering connection (phone %d, protocol: %s)\n", cphone,
  174.             proto->name);
  175.         connection_set(cphone, 0, proto);
  176.     }
  177. }
  178.  
  179. void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
  180. {
  181.     link_t *item;
  182.     pending_call_t *pcall;
  183.  
  184. //  printf("ipcp_call_in()\n");
  185. /*  printf("phone: %d, method: ", call->in_phone_hash);
  186.     ipc_m_print(IPC_GET_METHOD(*call));
  187.     printf(" args: (%u, %u, %u, %u, %u)\n",
  188.         IPC_GET_ARG1(*call),
  189.         IPC_GET_ARG2(*call),
  190.         IPC_GET_ARG3(*call),
  191.         IPC_GET_ARG4(*call),
  192.         IPC_GET_ARG5(*call)
  193.     );*/
  194.  
  195.     if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
  196.         /* Not a response */
  197.         printf("Not a response (hash %d)\n", hash);
  198.         return;
  199.     }
  200.  
  201.     hash = hash & ~IPC_CALLID_ANSWERED;
  202.  
  203.     item = hash_table_find(&pending_calls, &hash);
  204.     if (item == NULL) return; // No matching question found
  205.    
  206.     pcall = hash_table_get_instance(item, pending_call_t, link);
  207.  
  208.     printf("response matched to question\n");
  209.     hash_table_remove(&pending_calls, &hash, 1);
  210.  
  211.     parse_answer(pcall, call);
  212.     free(pcall);
  213. }
  214.  
  215. void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
  216. {
  217.     ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
  218.     ipcp_call_in(answer, IPCP_CALLID_SYNC);
  219. }
  220.  
  221. void ipcp_hangup(int phone, int rc)
  222. {
  223.     printf("hangup phone %d -> %d\n", phone, rc);
  224.     connection_clear(phone);
  225. }
  226.  
  227. /** @}
  228.  */
  229.