00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <adt/hash_table.h>
00038 #include <sys/typefmt.h>
00039
00040 #include "ipc_desc.h"
00041 #include "proto.h"
00042 #include "trace.h"
00043 #include "ipcp.h"
00044
00045 #define IPCP_CALLID_SYNC 0
00046
00047 typedef struct {
00048 sysarg_t phone_hash;
00049 ipc_call_t question;
00050 oper_t *oper;
00051
00052 ipc_callid_t call_hash;
00053
00054 link_t link;
00055 } pending_call_t;
00056
00057 typedef struct {
00058 int server;
00059 proto_t *proto;
00060 } connection_t;
00061
00062 #define MAX_PHONE 64
00063 connection_t connections[MAX_PHONE];
00064 int have_conn[MAX_PHONE];
00065
00066 #define PCALL_TABLE_CHAINS 32
00067 hash_table_t pending_calls;
00068
00069
00070
00071
00072 proto_t *proto_system;
00073 proto_t *proto_unknown;
00075 static hash_index_t pending_call_hash(unsigned long key[]);
00076 static int pending_call_compare(unsigned long key[], hash_count_t keys,
00077 link_t *item);
00078 static void pending_call_remove_callback(link_t *item);
00079
00080 hash_table_operations_t pending_call_ops = {
00081 .hash = pending_call_hash,
00082 .compare = pending_call_compare,
00083 .remove_callback = pending_call_remove_callback
00084 };
00085
00086
00087 static hash_index_t pending_call_hash(unsigned long key[])
00088 {
00089
00090 return key[0] % PCALL_TABLE_CHAINS;
00091 }
00092
00093 static int pending_call_compare(unsigned long key[], hash_count_t keys,
00094 link_t *item)
00095 {
00096 pending_call_t *hs;
00097
00098
00099 hs = hash_table_get_instance(item, pending_call_t, link);
00100
00101
00102 return key[0] == hs->call_hash;
00103 }
00104
00105 static void pending_call_remove_callback(link_t *item)
00106 {
00107
00108 }
00109
00110
00111 void ipcp_connection_set(int phone, int server, proto_t *proto)
00112 {
00113 if (phone <0 || phone >= MAX_PHONE) return;
00114 connections[phone].server = server;
00115 connections[phone].proto = proto;
00116 have_conn[phone] = 1;
00117 }
00118
00119 void ipcp_connection_clear(int phone)
00120 {
00121 have_conn[phone] = 0;
00122 connections[phone].server = 0;
00123 connections[phone].proto = NULL;
00124 }
00125
00126 static void ipc_m_print(proto_t *proto, sysarg_t method)
00127 {
00128 oper_t *oper;
00129
00130
00131 oper = proto_get_oper(proto_system, method);
00132
00133 if (oper == NULL && proto != NULL) {
00134
00135 oper = proto_get_oper(proto, method);
00136 }
00137
00138 if (oper != NULL) {
00139 printf("%s (%" PRIun ")", oper->name, method);
00140 return;
00141 }
00142
00143 printf("%" PRIun, method);
00144 }
00145
00146 void ipcp_init(void)
00147 {
00148 ipc_m_desc_t *desc;
00149 oper_t *oper;
00150
00151 val_type_t arg_def[OPER_MAX_ARGS] = {
00152 V_INTEGER,
00153 V_INTEGER,
00154 V_INTEGER,
00155 V_INTEGER,
00156 V_INTEGER
00157 };
00158
00159
00160
00161
00162 proto_unknown = proto_new("unknown");
00163
00164
00165
00166
00167
00168 proto_system = proto_new("system");
00169
00170 desc = ipc_methods;
00171 while (desc->number != 0) {
00172 oper = oper_new(desc->name, OPER_MAX_ARGS, arg_def, V_INTEGER,
00173 OPER_MAX_ARGS, arg_def);
00174 proto_add_oper(proto_system, desc->number, oper);
00175
00176 ++desc;
00177 }
00178
00179 hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
00180 }
00181
00182 void ipcp_cleanup(void)
00183 {
00184 proto_delete(proto_system);
00185 hash_table_destroy(&pending_calls);
00186 }
00187
00188 void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
00189 {
00190 pending_call_t *pcall;
00191 proto_t *proto;
00192 unsigned long key[1];
00193 oper_t *oper;
00194 sysarg_t *args;
00195 int i;
00196
00197 if (have_conn[phone]) proto = connections[phone].proto;
00198 else proto = NULL;
00199
00200 args = call->args;
00201
00202 if ((display_mask & DM_IPC) != 0) {
00203 printf("Call ID: %p, phone: %d, proto: %s, method: ",
00204 (void *) hash, phone,
00205 (proto ? proto->name : "n/a"));
00206 ipc_m_print(proto, IPC_GET_IMETHOD(*call));
00207 printf(" args: (%" PRIun ", %" PRIun ", %" PRIun ", "
00208 "%" PRIun ", %" PRIun ")\n",
00209 args[1], args[2], args[3], args[4], args[5]);
00210 }
00211
00212
00213 if ((display_mask & DM_USER) != 0) {
00214
00215 if (proto != NULL) {
00216 oper = proto_get_oper(proto, IPC_GET_IMETHOD(*call));
00217 } else {
00218 oper = NULL;
00219 }
00220
00221 if (oper != NULL) {
00222
00223 printf("%s(%d).%s", (proto ? proto->name : "n/a"),
00224 phone, (oper ? oper->name : "unknown"));
00225
00226 putchar('(');
00227 for (i = 1; i <= oper->argc; ++i) {
00228 if (i > 1) printf(", ");
00229 val_print(args[i], oper->arg_type[i - 1]);
00230 }
00231 putchar(')');
00232
00233 if (oper->rv_type == V_VOID && oper->respc == 0) {
00234
00235
00236
00237
00238
00239 putchar('.');
00240 }
00241
00242 putchar('\n');
00243 }
00244 } else {
00245 oper = NULL;
00246 }
00247
00248
00249
00250 pcall = malloc(sizeof(pending_call_t));
00251 pcall->phone_hash = phone;
00252 pcall->question = *call;
00253 pcall->call_hash = hash;
00254 pcall->oper = oper;
00255
00256 key[0] = hash;
00257
00258 hash_table_insert(&pending_calls, key, &pcall->link);
00259 }
00260
00261 static void parse_answer(ipc_callid_t hash, pending_call_t *pcall,
00262 ipc_call_t *answer)
00263 {
00264 sysarg_t phone;
00265 sysarg_t method;
00266 sysarg_t service;
00267 sysarg_t retval;
00268 proto_t *proto;
00269 int cphone;
00270
00271 sysarg_t *resp;
00272 oper_t *oper;
00273 int i;
00274
00275
00276
00277 phone = pcall->phone_hash;
00278 method = IPC_GET_IMETHOD(pcall->question);
00279 retval = IPC_GET_RETVAL(*answer);
00280
00281 resp = answer->args;
00282
00283 if ((display_mask & DM_IPC) != 0) {
00284 printf("Response to %p: retval=%" PRIdn ", args = (%" PRIun ", "
00285 "%" PRIun ", %" PRIun ", %" PRIun ", %" PRIun ")\n",
00286 (void *) hash, retval, IPC_GET_ARG1(*answer),
00287 IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer),
00288 IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer));
00289 }
00290
00291 if ((display_mask & DM_USER) != 0) {
00292 oper = pcall->oper;
00293
00294 if (oper != NULL && (oper->rv_type != V_VOID || oper->respc > 0)) {
00295 printf("->");
00296
00297 if (oper->rv_type != V_VOID) {
00298 putchar(' ');
00299 val_print(retval, oper->rv_type);
00300 }
00301
00302 if (oper->respc > 0) {
00303 putchar(' ');
00304 putchar('(');
00305 for (i = 1; i <= oper->respc; ++i) {
00306 if (i > 1) printf(", ");
00307 val_print(resp[i], oper->resp_type[i - 1]);
00308 }
00309 putchar(')');
00310 }
00311
00312 putchar('\n');
00313 }
00314 }
00315
00316 if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
00317
00318 service = IPC_GET_ARG1(pcall->question);
00319 proto = proto_get_by_srv(service);
00320 if (proto == NULL) proto = proto_unknown;
00321
00322 cphone = IPC_GET_ARG5(*answer);
00323 if ((display_mask & DM_SYSTEM) != 0) {
00324 printf("Registering connection (phone %d, protocol: %s)\n", cphone,
00325 proto->name);
00326 }
00327 ipcp_connection_set(cphone, 0, proto);
00328 }
00329 }
00330
00331 void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
00332 {
00333 link_t *item;
00334 pending_call_t *pcall;
00335 unsigned long key[1];
00336
00337
00338
00339 if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
00340
00341 if ((display_mask & DM_IPC) != 0) {
00342 printf("Not a response (hash %p)\n", (void *) hash);
00343 }
00344 return;
00345 }
00346
00347 hash = hash & ~IPC_CALLID_ANSWERED;
00348 key[0] = hash;
00349
00350 item = hash_table_find(&pending_calls, key);
00351 if (item == NULL) return;
00352
00353
00354
00355
00356
00357 pcall = hash_table_get_instance(item, pending_call_t, link);
00358 hash_table_remove(&pending_calls, key, 1);
00359
00360 parse_answer(hash, pcall, call);
00361 free(pcall);
00362 }
00363
00364 void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
00365 {
00366 ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
00367 ipcp_call_in(answer, IPCP_CALLID_SYNC);
00368 }
00369
00370 void ipcp_hangup(int phone, int rc)
00371 {
00372 if ((display_mask & DM_SYSTEM) != 0) {
00373 printf("Hang phone %d up -> %d\n", phone, rc);
00374 ipcp_connection_clear(phone);
00375 }
00376 }
00377