Subversion Repositories HelenOS

Rev

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

Rev Author Line No. Line
3438 svoboda 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 "ipcp.h"
42
 
43
#define IPCP_CALLID_SYNC 0
44
 
45
typedef struct {
46
    int phone_hash;
47
    ipc_call_t question;
48
 
49
    int call_hash;
50
 
51
    link_t link;
52
} pending_call_t;
53
 
54
typedef struct {
55
    int server;
56
    proto_t *proto;
57
} connection_t;
58
 
59
#define MAX_PHONE 64
60
connection_t connections[MAX_PHONE];
61
int have_conn[MAX_PHONE];
62
 
63
#define PCALL_TABLE_CHAINS 32
64
hash_table_t pending_calls;
65
 
3443 svoboda 66
/*
67
 * Pseudo-protocols
68
 */
69
proto_t *proto_system;      /**< Protocol describing system IPC methods. */
70
proto_t *proto_unknown;     /**< Protocol with no known methods. */
71
 
3438 svoboda 72
static hash_index_t pending_call_hash(unsigned long key[]);
73
static int pending_call_compare(unsigned long key[], hash_count_t keys,
74
    link_t *item);
75
static void pending_call_remove_callback(link_t *item);
76
 
77
hash_table_operations_t pending_call_ops = {
78
    .hash = pending_call_hash,
79
    .compare = pending_call_compare,
80
    .remove_callback = pending_call_remove_callback
81
};
82
 
83
 
84
static hash_index_t pending_call_hash(unsigned long key[])
85
{
86
//  printf("pending_call_hash\n");
87
    return key[0] % PCALL_TABLE_CHAINS;
88
}
89
 
90
static int pending_call_compare(unsigned long key[], hash_count_t keys,
91
    link_t *item)
92
{
93
    pending_call_t *hs;
94
 
95
//  printf("pending_call_compare\n");
96
    hs = hash_table_get_instance(item, pending_call_t, link);
97
 
98
    return key[0] == hs->call_hash;
99
}
100
 
101
static void pending_call_remove_callback(link_t *item)
102
{
103
//  printf("pending_call_remove_callback\n");
104
}
105
 
106
 
107
void ipcp_connection_set(int phone, int server, proto_t *proto)
108
{
109
    if (phone <0 || phone >= MAX_PHONE) return;
110
    connections[phone].server = server;
111
    connections[phone].proto = proto;
112
    have_conn[phone] = 1;
113
}
114
 
115
void ipcp_connection_clear(int phone)
116
{
117
    have_conn[phone] = 0;
118
    connections[phone].server = 0;
119
    connections[phone].proto = NULL;
120
}
121
 
122
static void ipc_m_print(proto_t *proto, ipcarg_t method)
123
{
124
    oper_t *oper;
125
 
3443 svoboda 126
    /* Try system methods first */
127
    oper = proto_get_oper(proto_system, method);
3438 svoboda 128
 
3443 svoboda 129
    if (oper == NULL && proto != NULL) {
130
        /* Not a system method, try the user protocol. */
131
        oper = proto_get_oper(proto, method);
3438 svoboda 132
    }
133
 
3443 svoboda 134
    if (oper != NULL) {
135
        printf("%s (%d)", oper->name, method);
136
        return;
3438 svoboda 137
    }
138
 
139
    printf("%d", method);
140
}
141
 
142
void ipcp_init(void)
143
{
3443 svoboda 144
    ipc_m_desc_t *desc;
145
    oper_t *oper;
146
 
147
    /*
148
     * Create a pseudo-protocol 'unknown' that has no known methods.
149
     */
150
    proto_unknown = proto_new("unknown");
151
 
152
    /*
153
     * Create a pseudo-protocol 'system' defining names of system IPC
154
     * methods.
155
     */
156
    proto_system = proto_new("system");
157
 
158
    desc = ipc_methods;
159
    while (desc->number != 0) {
160
        oper = oper_new(desc->name);
161
        proto_add_oper(proto_system, desc->number, oper);
162
 
163
        ++desc;
164
    }
165
 
3438 svoboda 166
    hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
167
}
168
 
169
void ipcp_cleanup(void)
170
{
3443 svoboda 171
    proto_delete(proto_system);
3438 svoboda 172
    hash_table_destroy(&pending_calls);
173
}
174
 
175
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
176
{
177
    pending_call_t *pcall;
178
    proto_t *proto;
179
    unsigned long key[1];
180
 
181
    if (have_conn[phone]) proto = connections[phone].proto;
182
    else proto = NULL;
183
 
184
//  printf("ipcp_call_out()\n");
185
    printf("call id: 0x%x, phone: %d, proto: %s, method: ", hash, phone,
186
        (proto ? proto->name : "n/a"));
187
    ipc_m_print(proto, IPC_GET_METHOD(*call));
188
    printf(" args: (%u, %u, %u, %u, %u)\n",
189
        IPC_GET_ARG1(*call),
190
        IPC_GET_ARG2(*call),
191
        IPC_GET_ARG3(*call),
192
        IPC_GET_ARG4(*call),
193
        IPC_GET_ARG5(*call)
194
    );
195
 
196
    /* Store call in hash table for response matching */
197
 
198
    pcall = malloc(sizeof(pending_call_t));
199
    pcall->phone_hash = phone;
200
    pcall->question = *call;
201
    pcall->call_hash = hash;
202
 
203
    key[0] = hash;
204
 
205
    hash_table_insert(&pending_calls, key, &pcall->link);
206
}
207
 
208
static void parse_answer(pending_call_t *pcall, ipc_call_t *answer)
209
{
210
    int phone;
211
    ipcarg_t method;
212
    ipcarg_t service;
213
    int retval;
214
    proto_t *proto;
215
    int cphone;
216
 
217
//  printf("parse_answer\n");
218
 
219
    phone = pcall->phone_hash;
220
    method = IPC_GET_METHOD(pcall->question);
221
    retval = IPC_GET_RETVAL(*answer);
222
    printf("phone=%d, method=%d, retval=%d\n",
223
        phone, method, retval);
224
 
225
    if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
226
        /* Connected to a service (through NS) */
227
        service = IPC_GET_ARG1(pcall->question);
228
        proto = proto_get_by_srv(service);
3443 svoboda 229
        if (proto == NULL) proto = proto_unknown;
3438 svoboda 230
 
231
        cphone = IPC_GET_ARG5(*answer);
232
        printf("registering connection (phone %d, protocol: %s)\n", cphone,
233
            proto->name);
234
        ipcp_connection_set(cphone, 0, proto);
235
    }
236
}
237
 
238
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
239
{
240
    link_t *item;
241
    pending_call_t *pcall;
242
    unsigned long key[1];
243
 
244
//  printf("ipcp_call_in()\n");
245
/*  printf("phone: %d, method: ", call->in_phone_hash);
246
    ipc_m_print(IPC_GET_METHOD(*call));
247
    printf(" args: (%u, %u, %u, %u, %u)\n",
248
        IPC_GET_ARG1(*call),
249
        IPC_GET_ARG2(*call),
250
        IPC_GET_ARG3(*call),
251
        IPC_GET_ARG4(*call),
252
        IPC_GET_ARG5(*call)
253
    );*/
254
 
255
    if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
256
        /* Not a response */
257
        printf("Not a response (hash %d)\n", hash);
258
        return;
259
    }
260
 
261
    hash = hash & ~IPC_CALLID_ANSWERED;
262
    key[0] = hash;
263
 
264
    item = hash_table_find(&pending_calls, key);
265
    if (item == NULL) return; // No matching question found
266
 
267
    pcall = hash_table_get_instance(item, pending_call_t, link);
268
 
269
    printf("response matched to question\n");
270
    hash_table_remove(&pending_calls, key, 1);
271
 
272
    parse_answer(pcall, call);
273
    free(pcall);
274
}
275
 
276
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
277
{
278
    ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
279
    ipcp_call_in(answer, IPCP_CALLID_SYNC);
280
}
281
 
282
void ipcp_hangup(int phone, int rc)
283
{
284
    printf("hangup phone %d -> %d\n", phone, rc);
285
    ipcp_connection_clear(phone);
286
}
287
 
288
/** @}
289
 */