Subversion Repositories HelenOS

Rev

Rev 3438 | Rev 3444 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3438 Rev 3443
1
/*
1
/*
2
 * Copyright (c) 2008 Jiri Svoboda
2
 * Copyright (c) 2008 Jiri Svoboda
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup trace
29
/** @addtogroup trace
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <stdio.h>
35
#include <stdio.h>
36
#include <stdlib.h>
36
#include <stdlib.h>
37
#include <libadt/hash_table.h>
37
#include <libadt/hash_table.h>
38
 
38
 
39
#include "ipc_desc.h"
39
#include "ipc_desc.h"
40
#include "proto.h"
40
#include "proto.h"
41
#include "ipcp.h"
41
#include "ipcp.h"
42
 
42
 
43
#define IPCP_CALLID_SYNC 0
43
#define IPCP_CALLID_SYNC 0
44
 
44
 
45
typedef struct {
45
typedef struct {
46
    int phone_hash;
46
    int phone_hash;
47
    ipc_call_t question;
47
    ipc_call_t question;
48
 
48
 
49
    int call_hash;
49
    int call_hash;
50
 
50
 
51
    link_t link;
51
    link_t link;
52
} pending_call_t;
52
} pending_call_t;
53
 
53
 
54
typedef struct {
54
typedef struct {
55
    int server;
55
    int server;
56
    proto_t *proto;
56
    proto_t *proto;
57
} connection_t;
57
} connection_t;
58
 
58
 
59
#define MAX_PHONE 64
59
#define MAX_PHONE 64
60
connection_t connections[MAX_PHONE];
60
connection_t connections[MAX_PHONE];
61
int have_conn[MAX_PHONE];
61
int have_conn[MAX_PHONE];
62
 
62
 
63
#define PCALL_TABLE_CHAINS 32
63
#define PCALL_TABLE_CHAINS 32
64
hash_table_t pending_calls;
64
hash_table_t pending_calls;
65
 
65
 
-
 
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
 
66
static hash_index_t pending_call_hash(unsigned long key[]);
72
static hash_index_t pending_call_hash(unsigned long key[]);
67
static int pending_call_compare(unsigned long key[], hash_count_t keys,
73
static int pending_call_compare(unsigned long key[], hash_count_t keys,
68
    link_t *item);
74
    link_t *item);
69
static void pending_call_remove_callback(link_t *item);
75
static void pending_call_remove_callback(link_t *item);
70
 
76
 
71
hash_table_operations_t pending_call_ops = {
77
hash_table_operations_t pending_call_ops = {
72
    .hash = pending_call_hash,
78
    .hash = pending_call_hash,
73
    .compare = pending_call_compare,
79
    .compare = pending_call_compare,
74
    .remove_callback = pending_call_remove_callback
80
    .remove_callback = pending_call_remove_callback
75
};
81
};
76
 
82
 
77
 
83
 
78
static hash_index_t pending_call_hash(unsigned long key[])
84
static hash_index_t pending_call_hash(unsigned long key[])
79
{
85
{
80
//  printf("pending_call_hash\n");
86
//  printf("pending_call_hash\n");
81
    return key[0] % PCALL_TABLE_CHAINS;
87
    return key[0] % PCALL_TABLE_CHAINS;
82
}
88
}
83
 
89
 
84
static int pending_call_compare(unsigned long key[], hash_count_t keys,
90
static int pending_call_compare(unsigned long key[], hash_count_t keys,
85
    link_t *item)
91
    link_t *item)
86
{
92
{
87
    pending_call_t *hs;
93
    pending_call_t *hs;
88
 
94
 
89
//  printf("pending_call_compare\n");
95
//  printf("pending_call_compare\n");
90
    hs = hash_table_get_instance(item, pending_call_t, link);
96
    hs = hash_table_get_instance(item, pending_call_t, link);
91
 
97
 
92
    return key[0] == hs->call_hash;
98
    return key[0] == hs->call_hash;
93
}
99
}
94
 
100
 
95
static void pending_call_remove_callback(link_t *item)
101
static void pending_call_remove_callback(link_t *item)
96
{
102
{
97
//  printf("pending_call_remove_callback\n");
103
//  printf("pending_call_remove_callback\n");
98
}
104
}
99
 
105
 
100
 
106
 
101
void ipcp_connection_set(int phone, int server, proto_t *proto)
107
void ipcp_connection_set(int phone, int server, proto_t *proto)
102
{
108
{
103
    if (phone <0 || phone >= MAX_PHONE) return;
109
    if (phone <0 || phone >= MAX_PHONE) return;
104
    connections[phone].server = server;
110
    connections[phone].server = server;
105
    connections[phone].proto = proto;
111
    connections[phone].proto = proto;
106
    have_conn[phone] = 1;
112
    have_conn[phone] = 1;
107
}
113
}
108
 
114
 
109
void ipcp_connection_clear(int phone)
115
void ipcp_connection_clear(int phone)
110
{
116
{
111
    have_conn[phone] = 0;
117
    have_conn[phone] = 0;
112
    connections[phone].server = 0;
118
    connections[phone].server = 0;
113
    connections[phone].proto = NULL;
119
    connections[phone].proto = NULL;
114
}
120
}
115
 
121
 
116
static void ipc_m_print(proto_t *proto, ipcarg_t method)
122
static void ipc_m_print(proto_t *proto, ipcarg_t method)
117
{
123
{
118
    ipc_m_desc_t *desc;
-
 
119
    oper_t *oper;
124
    oper_t *oper;
120
 
125
 
121
    /* FIXME: too slow */
126
    /* Try system methods first */
122
    desc = ipc_methods;
-
 
123
    while (desc->number != 0) {
-
 
124
        if (desc->number == method) {
-
 
125
            printf("%s (%d)", desc->name, method);
127
    oper = proto_get_oper(proto_system, method);
126
            return;
-
 
127
        }
-
 
128
 
128
 
-
 
129
    if (oper == NULL && proto != NULL) {
-
 
130
        /* Not a system method, try the user protocol. */
129
        ++desc;
131
        oper = proto_get_oper(proto, method);
130
    }
132
    }
131
 
133
 
132
    if (proto != NULL) {
-
 
133
        oper = proto_get_oper(proto, method);
-
 
134
        if (oper != NULL) {
134
    if (oper != NULL) {
135
            printf("%s (%d)", oper->name, method);
135
        printf("%s (%d)", oper->name, method);
136
            return;
136
        return;
137
        }
-
 
138
    }
137
    }
139
 
138
 
140
    printf("%d", method);
139
    printf("%d", method);
141
}
140
}
142
 
141
 
143
void ipcp_init(void)
142
void ipcp_init(void)
144
{
143
{
-
 
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
 
145
    hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
166
    hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
146
}
167
}
147
 
168
 
148
void ipcp_cleanup(void)
169
void ipcp_cleanup(void)
149
{
170
{
-
 
171
    proto_delete(proto_system);
150
    hash_table_destroy(&pending_calls);
172
    hash_table_destroy(&pending_calls);
151
}
173
}
152
 
174
 
153
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
175
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
154
{
176
{
155
    pending_call_t *pcall;
177
    pending_call_t *pcall;
156
    proto_t *proto;
178
    proto_t *proto;
157
    unsigned long key[1];
179
    unsigned long key[1];
158
 
180
 
159
    if (have_conn[phone]) proto = connections[phone].proto;
181
    if (have_conn[phone]) proto = connections[phone].proto;
160
    else proto = NULL;
182
    else proto = NULL;
161
 
183
 
162
//  printf("ipcp_call_out()\n");
184
//  printf("ipcp_call_out()\n");
163
    printf("call id: 0x%x, phone: %d, proto: %s, method: ", hash, phone,
185
    printf("call id: 0x%x, phone: %d, proto: %s, method: ", hash, phone,
164
        (proto ? proto->name : "n/a"));
186
        (proto ? proto->name : "n/a"));
165
    ipc_m_print(proto, IPC_GET_METHOD(*call));
187
    ipc_m_print(proto, IPC_GET_METHOD(*call));
166
    printf(" args: (%u, %u, %u, %u, %u)\n",
188
    printf(" args: (%u, %u, %u, %u, %u)\n",
167
        IPC_GET_ARG1(*call),
189
        IPC_GET_ARG1(*call),
168
        IPC_GET_ARG2(*call),
190
        IPC_GET_ARG2(*call),
169
        IPC_GET_ARG3(*call),
191
        IPC_GET_ARG3(*call),
170
        IPC_GET_ARG4(*call),
192
        IPC_GET_ARG4(*call),
171
        IPC_GET_ARG5(*call)
193
        IPC_GET_ARG5(*call)
172
    );
194
    );
173
 
195
 
174
    /* Store call in hash table for response matching */
196
    /* Store call in hash table for response matching */
175
 
197
 
176
    pcall = malloc(sizeof(pending_call_t));
198
    pcall = malloc(sizeof(pending_call_t));
177
    pcall->phone_hash = phone;
199
    pcall->phone_hash = phone;
178
    pcall->question = *call;
200
    pcall->question = *call;
179
    pcall->call_hash = hash;
201
    pcall->call_hash = hash;
180
 
202
 
181
    key[0] = hash;
203
    key[0] = hash;
182
 
204
 
183
    hash_table_insert(&pending_calls, key, &pcall->link);
205
    hash_table_insert(&pending_calls, key, &pcall->link);
184
}
206
}
185
 
207
 
186
static void parse_answer(pending_call_t *pcall, ipc_call_t *answer)
208
static void parse_answer(pending_call_t *pcall, ipc_call_t *answer)
187
{
209
{
188
    int phone;
210
    int phone;
189
    ipcarg_t method;
211
    ipcarg_t method;
190
    ipcarg_t service;
212
    ipcarg_t service;
191
    int retval;
213
    int retval;
192
    static proto_t proto_unknown = { .name = "unknown" };
-
 
193
    proto_t *proto;
214
    proto_t *proto;
194
    int cphone;
215
    int cphone;
195
 
216
 
196
//  printf("parse_answer\n");
217
//  printf("parse_answer\n");
197
 
218
 
198
    phone = pcall->phone_hash;
219
    phone = pcall->phone_hash;
199
    method = IPC_GET_METHOD(pcall->question);
220
    method = IPC_GET_METHOD(pcall->question);
200
    retval = IPC_GET_RETVAL(*answer);
221
    retval = IPC_GET_RETVAL(*answer);
201
    printf("phone=%d, method=%d, retval=%d\n",
222
    printf("phone=%d, method=%d, retval=%d\n",
202
        phone, method, retval);
223
        phone, method, retval);
203
 
224
 
204
    if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
225
    if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
205
        /* Connected to a service (through NS) */
226
        /* Connected to a service (through NS) */
206
        service = IPC_GET_ARG1(pcall->question);
227
        service = IPC_GET_ARG1(pcall->question);
207
        proto = proto_get_by_srv(service);
228
        proto = proto_get_by_srv(service);
208
        if (proto == NULL) proto = &proto_unknown;
229
        if (proto == NULL) proto = proto_unknown;
209
 
230
 
210
        cphone = IPC_GET_ARG5(*answer);
231
        cphone = IPC_GET_ARG5(*answer);
211
        printf("registering connection (phone %d, protocol: %s)\n", cphone,
232
        printf("registering connection (phone %d, protocol: %s)\n", cphone,
212
            proto->name);
233
            proto->name);
213
        ipcp_connection_set(cphone, 0, proto);
234
        ipcp_connection_set(cphone, 0, proto);
214
    }
235
    }
215
}
236
}
216
 
237
 
217
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
238
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
218
{
239
{
219
    link_t *item;
240
    link_t *item;
220
    pending_call_t *pcall;
241
    pending_call_t *pcall;
221
    unsigned long key[1];
242
    unsigned long key[1];
222
 
243
 
223
//  printf("ipcp_call_in()\n");
244
//  printf("ipcp_call_in()\n");
224
/*  printf("phone: %d, method: ", call->in_phone_hash);
245
/*  printf("phone: %d, method: ", call->in_phone_hash);
225
    ipc_m_print(IPC_GET_METHOD(*call));
246
    ipc_m_print(IPC_GET_METHOD(*call));
226
    printf(" args: (%u, %u, %u, %u, %u)\n",
247
    printf(" args: (%u, %u, %u, %u, %u)\n",
227
        IPC_GET_ARG1(*call),
248
        IPC_GET_ARG1(*call),
228
        IPC_GET_ARG2(*call),
249
        IPC_GET_ARG2(*call),
229
        IPC_GET_ARG3(*call),
250
        IPC_GET_ARG3(*call),
230
        IPC_GET_ARG4(*call),
251
        IPC_GET_ARG4(*call),
231
        IPC_GET_ARG5(*call)
252
        IPC_GET_ARG5(*call)
232
    );*/
253
    );*/
233
 
254
 
234
    if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
255
    if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
235
        /* Not a response */
256
        /* Not a response */
236
        printf("Not a response (hash %d)\n", hash);
257
        printf("Not a response (hash %d)\n", hash);
237
        return;
258
        return;
238
    }
259
    }
239
 
260
 
240
    hash = hash & ~IPC_CALLID_ANSWERED;
261
    hash = hash & ~IPC_CALLID_ANSWERED;
241
    key[0] = hash;
262
    key[0] = hash;
242
 
263
 
243
    item = hash_table_find(&pending_calls, key);
264
    item = hash_table_find(&pending_calls, key);
244
    if (item == NULL) return; // No matching question found
265
    if (item == NULL) return; // No matching question found
245
   
266
   
246
    pcall = hash_table_get_instance(item, pending_call_t, link);
267
    pcall = hash_table_get_instance(item, pending_call_t, link);
247
 
268
 
248
    printf("response matched to question\n");
269
    printf("response matched to question\n");
249
    hash_table_remove(&pending_calls, key, 1);
270
    hash_table_remove(&pending_calls, key, 1);
250
 
271
 
251
    parse_answer(pcall, call);
272
    parse_answer(pcall, call);
252
    free(pcall);
273
    free(pcall);
253
}
274
}
254
 
275
 
255
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
276
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
256
{
277
{
257
    ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
278
    ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
258
    ipcp_call_in(answer, IPCP_CALLID_SYNC);
279
    ipcp_call_in(answer, IPCP_CALLID_SYNC);
259
}
280
}
260
 
281
 
261
void ipcp_hangup(int phone, int rc)
282
void ipcp_hangup(int phone, int rc)
262
{
283
{
263
    printf("hangup phone %d -> %d\n", phone, rc);
284
    printf("hangup phone %d -> %d\n", phone, rc);
264
    ipcp_connection_clear(phone);
285
    ipcp_connection_clear(phone);
265
}
286
}
266
 
287
 
267
/** @}
288
/** @}
268
 */
289
 */
269
 
290