HelenOS sources
This source file includes following definitions.
- pending_call_key_hash
- pending_call_hash
- pending_call_key_equal
- ipcp_connection_set
- ipcp_connection_clear
- ipc_m_print
- ipcp_init
- ipcp_cleanup
- ipcp_call_out
- parse_answer
- ipcp_call_in
- ipcp_hangup
#include <stdio.h>
#include <stdlib.h>
#include <str_error.h>
#include <inttypes.h>
#include <adt/hash_table.h>
#include <abi/ipc/methods.h>
#include <macros.h>
#include "ipc_desc.h"
#include "proto.h"
#include "trace.h"
#include "ipcp.h"
typedef struct {
cap_phone_handle_t phone_handle;
ipc_call_t question;
oper_t *oper;
cap_call_handle_t call_handle;
ht_link_t link;
} pending_call_t;
typedef struct {
int server;
proto_t *proto;
} connection_t;
#define MAX_PHONE 64
connection_t connections[MAX_PHONE];
int have_conn[MAX_PHONE];
static hash_table_t pending_calls;
proto_t *proto_system;
proto_t *proto_unknown;
static size_t pending_call_key_hash(const void *key)
{
const cap_call_handle_t *chandle = key;
return cap_handle_raw(*chandle);
}
static size_t pending_call_hash(const ht_link_t *item)
{
pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
return cap_handle_raw(hs->call_handle);
}
static bool pending_call_key_equal(const void *key, const ht_link_t *item)
{
const cap_call_handle_t *chandle = key;
pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
return *chandle == hs->call_handle;
}
static const hash_table_ops_t pending_call_ops = {
.hash = pending_call_hash,
.key_hash = pending_call_key_hash,
.key_equal = pending_call_key_equal,
.equal = NULL,
.remove_callback = NULL
};
void ipcp_connection_set(cap_phone_handle_t phone, int server, proto_t *proto)
{
if (cap_handle_raw(phone) < 0 || cap_handle_raw(phone) >= MAX_PHONE)
return;
connections[cap_handle_raw(phone)].server = server;
connections[cap_handle_raw(phone)].proto = proto;
have_conn[cap_handle_raw(phone)] = 1;
}
void ipcp_connection_clear(cap_phone_handle_t phone)
{
have_conn[cap_handle_raw(phone)] = 0;
connections[cap_handle_raw(phone)].server = 0;
connections[cap_handle_raw(phone)].proto = NULL;
}
static void ipc_m_print(proto_t *proto, sysarg_t method)
{
oper_t *oper;
oper = proto_get_oper(proto_system, method);
if (oper == NULL && proto != NULL) {
oper = proto_get_oper(proto, method);
}
if (oper != NULL) {
printf("%s (%" PRIun ")", oper->name, method);
return;
}
printf("%" PRIun, method);
}
void ipcp_init(void)
{
val_type_t arg_def[OPER_MAX_ARGS] = {
V_INTEGER,
V_INTEGER,
V_INTEGER,
V_INTEGER,
V_INTEGER
};
proto_unknown = proto_new("unknown");
proto_system = proto_new("system");
for (size_t i = 0; i < ipc_methods_len; i++) {
oper_t *oper = oper_new(ipc_methods[i].name, OPER_MAX_ARGS,
arg_def, V_INTEGER, OPER_MAX_ARGS, arg_def);
proto_add_oper(proto_system, ipc_methods[i].number, oper);
}
bool ok = hash_table_create(&pending_calls, 0, 0, &pending_call_ops);
assert(ok);
}
void ipcp_cleanup(void)
{
proto_delete(proto_system);
hash_table_destroy(&pending_calls);
}
void ipcp_call_out(cap_phone_handle_t phandle, ipc_call_t *call,
cap_call_handle_t chandle)
{
pending_call_t *pcall;
proto_t *proto;
oper_t *oper;
sysarg_t *args;
int i;
if (have_conn[cap_handle_raw(phandle)])
proto = connections[cap_handle_raw(phandle)].proto;
else
proto = NULL;
args = call->args;
if ((display_mask & DM_IPC) != 0) {
printf("Call handle: %p, phone: %p, proto: %s, method: ",
chandle, phandle, (proto ? proto->name : "n/a"));
ipc_m_print(proto, ipc_get_imethod(call));
printf(" args: (%" PRIun ", %" PRIun ", %" PRIun ", "
"%" PRIun ", %" PRIun ")\n",
args[1], args[2], args[3], args[4], args[5]);
}
if ((display_mask & DM_USER) != 0) {
if (proto != NULL) {
oper = proto_get_oper(proto, ipc_get_imethod(call));
} else {
oper = NULL;
}
if (oper != NULL) {
printf("%s(%p).%s", (proto ? proto->name : "n/a"),
phandle, (oper ? oper->name : "unknown"));
putchar('(');
for (i = 1; i <= oper->argc; ++i) {
if (i > 1)
printf(", ");
val_print(args[i], oper->arg_type[i - 1]);
}
putchar(')');
if (oper->rv_type == V_VOID && oper->respc == 0) {
putchar('.');
}
putchar('\n');
}
} else {
oper = NULL;
}
pcall = malloc(sizeof(pending_call_t));
pcall->phone_handle = phandle;
pcall->question = *call;
pcall->call_handle = chandle;
pcall->oper = oper;
hash_table_insert(&pending_calls, &pcall->link);
}
static void parse_answer(cap_call_handle_t call_handle, pending_call_t *pcall,
ipc_call_t *answer)
{
cap_phone_handle_t phone;
sysarg_t method;
sysarg_t service;
errno_t retval;
proto_t *proto;
cap_phone_handle_t cphone;
sysarg_t *resp;
oper_t *oper;
int i;
phone = pcall->phone_handle;
method = ipc_get_imethod(&pcall->question);
retval = ipc_get_retval(answer);
resp = answer->args;
if ((display_mask & DM_IPC) != 0) {
printf("Response to %p: retval=%s, args = (%" PRIun ", "
"%" PRIun ", %" PRIun ", %" PRIun ", %" PRIun ")\n",
call_handle, str_error_name(retval), ipc_get_arg1(answer),
ipc_get_arg2(answer), ipc_get_arg3(answer),
ipc_get_arg4(answer), ipc_get_arg5(answer));
}
if ((display_mask & DM_USER) != 0) {
oper = pcall->oper;
if ((oper != NULL) &&
((oper->rv_type != V_VOID) || (oper->respc > 0))) {
printf("->");
if (oper->rv_type != V_VOID) {
putchar(' ');
val_print((sysarg_t) retval, oper->rv_type);
}
if (oper->respc > 0) {
putchar(' ');
putchar('(');
for (i = 1; i <= oper->respc; ++i) {
if (i > 1)
printf(", ");
val_print(resp[i], oper->resp_type[i - 1]);
}
putchar(')');
}
putchar('\n');
}
}
if ((phone == PHONE_NS) && (method == IPC_M_CONNECT_ME_TO) &&
(retval == 0)) {
service = ipc_get_arg2(&pcall->question);
proto = proto_get_by_srv(service);
if (proto == NULL)
proto = proto_unknown;
cphone = (cap_phone_handle_t) ipc_get_arg5(answer);
if ((display_mask & DM_SYSTEM) != 0) {
printf("Registering connection (phone %p, protocol: %s)\n", cphone,
proto->name);
}
ipcp_connection_set(cphone, 0, proto);
}
}
void ipcp_call_in(ipc_call_t *call, cap_call_handle_t chandle)
{
ht_link_t *item;
pending_call_t *pcall;
if ((call->flags & IPC_CALL_ANSWERED) == 0) {
if ((display_mask & DM_IPC) != 0) {
printf("Not a response (handle %p)\n", chandle);
}
return;
}
item = hash_table_find(&pending_calls, &chandle);
if (item == NULL)
return;
pcall = hash_table_get_inst(item, pending_call_t, link);
hash_table_remove(&pending_calls, &chandle);
parse_answer(chandle, pcall, call);
free(pcall);
}
void ipcp_hangup(cap_phone_handle_t phone, errno_t rc)
{
if ((display_mask & DM_SYSTEM) != 0) {
printf("Hang up phone %p -> %s\n", phone, str_error_name(rc));
ipcp_connection_clear(phone);
}
}
HelenOS homepage, sources at GitHub