Subversion Repositories HelenOS

Rev

Rev 2880 | Rev 2894 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2871 svoboda 1
/** @addtogroup sctrace
2
 * @{
3
 */
4
/** @file
5
 */
6
 
7
#include <stdio.h>
2873 svoboda 8
#include <stdlib.h>
9
#include <libadt/hash_table.h>
2871 svoboda 10
 
11
#include "ipc_desc.h"
2878 svoboda 12
#include "proto.h"
2874 svoboda 13
#include "ipcp.h"
2871 svoboda 14
 
2877 svoboda 15
#define IPCP_CALLID_SYNC 0
16
 
2873 svoboda 17
typedef struct {
2874 svoboda 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 {
2873 svoboda 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[])
2871 svoboda 39
{
2877 svoboda 40
//  printf("pending_call_hash\n");
2873 svoboda 41
    return key[0] % PCALL_TABLE_CHAINS;
42
}
43
 
2877 svoboda 44
int pending_call_compare(unsigned long key[], hash_count_t keys,
45
    link_t *item)
2873 svoboda 46
{
47
    pending_call_t *hs;
48
 
2877 svoboda 49
//  printf("pending_call_compare\n");
2873 svoboda 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
{
2877 svoboda 57
//  printf("pending_call_remove_callback\n");
2873 svoboda 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
 
2882 svoboda 66
void ipcp_connection_set(int phone, int server, proto_t *proto)
2873 svoboda 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
 
2882 svoboda 74
void ipcp_connection_clear(int phone)
2873 svoboda 75
{
76
    have_conn[phone] = 0;
77
    connections[phone].server = 0;
78
    connections[phone].proto = NULL;
79
}
80
 
2880 svoboda 81
static void ipc_m_print(proto_t *proto, ipcarg_t method)
2873 svoboda 82
{
2872 svoboda 83
    ipc_m_desc_t *desc;
2880 svoboda 84
    oper_t *oper;
2872 svoboda 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
 
2880 svoboda 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
 
2872 svoboda 105
    printf("%d", method);
106
}
107
 
2873 svoboda 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
 
2874 svoboda 118
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
2872 svoboda 119
{
2873 svoboda 120
    pending_call_t *pcall;
2880 svoboda 121
    proto_t *proto;
2873 svoboda 122
 
2880 svoboda 123
    if (have_conn[phone]) proto = connections[phone].proto;
124
    else proto = NULL;
2877 svoboda 125
 
2874 svoboda 126
//  printf("ipcp_call_out()\n");
2877 svoboda 127
    printf("call id: 0x%x, phone: %d, proto: %s, method: ", hash, phone,
2880 svoboda 128
        (proto ? proto->name : "n/a"));
129
    ipc_m_print(proto, IPC_GET_METHOD(*call));
2872 svoboda 130
    printf(" args: (%u, %u, %u, %u, %u)\n",
2871 svoboda 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
    );
2873 svoboda 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);
2871 svoboda 146
}
147
 
2877 svoboda 148
static void parse_answer(pending_call_t *pcall, ipc_call_t *answer)
149
{
150
    int phone;
151
    ipcarg_t method;
2878 svoboda 152
    ipcarg_t service;
2877 svoboda 153
    int retval;
2878 svoboda 154
    static proto_t proto_unknown = { .name = "unknown" };
155
    proto_t *proto;
2877 svoboda 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) */
2878 svoboda 168
        service = IPC_GET_ARG1(pcall->question);
169
        proto = proto_get_by_srv(service);
170
        if (proto == NULL) proto = &proto_unknown;
171
 
2877 svoboda 172
        cphone = IPC_GET_ARG5(*answer);
2878 svoboda 173
        printf("registering connection (phone %d, protocol: %s)\n", cphone,
174
            proto->name);
2882 svoboda 175
        ipcp_connection_set(cphone, 0, proto);
2877 svoboda 176
    }
177
}
178
 
2874 svoboda 179
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
2871 svoboda 180
{
2873 svoboda 181
    link_t *item;
182
    pending_call_t *pcall;
183
 
2874 svoboda 184
//  printf("ipcp_call_in()\n");
2872 svoboda 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",
2871 svoboda 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)
2872 svoboda 193
    );*/
2873 svoboda 194
 
2877 svoboda 195
    if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
2873 svoboda 196
        /* Not a response */
2877 svoboda 197
        printf("Not a response (hash %d)\n", hash);
2873 svoboda 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);
2877 svoboda 210
 
211
    parse_answer(pcall, call);
212
    free(pcall);
2871 svoboda 213
}
214
 
2874 svoboda 215
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
2872 svoboda 216
{
2877 svoboda 217
    ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
218
    ipcp_call_in(answer, IPCP_CALLID_SYNC);
2872 svoboda 219
}
2871 svoboda 220
 
2874 svoboda 221
void ipcp_hangup(int phone, int rc)
2872 svoboda 222
{
223
    printf("hangup phone %d -> %d\n", phone, rc);
2882 svoboda 224
    ipcp_connection_clear(phone);
2872 svoboda 225
}
226
 
2871 svoboda 227
/** @}
228
 */