source: mainline/uspace/app/trace/ipcp.c@ 5e801dc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5e801dc was 5e801dc, checked in by GitHub <noreply@…>, 6 years ago

Indicate and enforce constness of hash table key in certain functions (#158)

The assumption here is that modifying key in the hash/equal functions in something completely unexpected, and not something you would ever want to do intentionally, so it makes sense to disallow it entirely to get that extra level of checking.

  • Property mode set to 100644
File size: 8.8 KB
Line 
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 <str_error.h>
38#include <inttypes.h>
39#include <adt/hash_table.h>
40#include <abi/ipc/methods.h>
41#include <macros.h>
42#include "ipc_desc.h"
43#include "proto.h"
44#include "trace.h"
45#include "ipcp.h"
46
47typedef struct {
48 cap_phone_handle_t phone_handle;
49 ipc_call_t question;
50 oper_t *oper;
51
52 cap_call_handle_t call_handle;
53
54 ht_link_t link;
55} pending_call_t;
56
57typedef struct {
58 int server;
59 proto_t *proto;
60} connection_t;
61
62#define MAX_PHONE 64
63connection_t connections[MAX_PHONE];
64int have_conn[MAX_PHONE];
65
66static hash_table_t pending_calls;
67
68/*
69 * Pseudo-protocols
70 */
71proto_t *proto_system; /**< Protocol describing system IPC methods. */
72proto_t *proto_unknown; /**< Protocol with no known methods. */
73
74static size_t pending_call_key_hash(const void *key)
75{
76 const cap_call_handle_t *chandle = key;
77 return cap_handle_raw(*chandle);
78}
79
80static size_t pending_call_hash(const ht_link_t *item)
81{
82 pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
83 return cap_handle_raw(hs->call_handle);
84}
85
86static bool pending_call_key_equal(const void *key, const ht_link_t *item)
87{
88 const cap_call_handle_t *chandle = key;
89 pending_call_t *hs = hash_table_get_inst(item, pending_call_t, link);
90
91 return *chandle == hs->call_handle;
92}
93
94static hash_table_ops_t pending_call_ops = {
95 .hash = pending_call_hash,
96 .key_hash = pending_call_key_hash,
97 .key_equal = pending_call_key_equal,
98 .equal = NULL,
99 .remove_callback = NULL
100};
101
102void ipcp_connection_set(cap_phone_handle_t phone, int server, proto_t *proto)
103{
104 // XXX: there is no longer a limit on the number of phones as phones are
105 // now handled using capabilities
106 if (cap_handle_raw(phone) < 0 || cap_handle_raw(phone) >= MAX_PHONE)
107 return;
108 connections[cap_handle_raw(phone)].server = server;
109 connections[cap_handle_raw(phone)].proto = proto;
110 have_conn[cap_handle_raw(phone)] = 1;
111}
112
113void ipcp_connection_clear(cap_phone_handle_t phone)
114{
115 have_conn[cap_handle_raw(phone)] = 0;
116 connections[cap_handle_raw(phone)].server = 0;
117 connections[cap_handle_raw(phone)].proto = NULL;
118}
119
120static void ipc_m_print(proto_t *proto, sysarg_t method)
121{
122 oper_t *oper;
123
124 /* Try system methods first */
125 oper = proto_get_oper(proto_system, method);
126
127 if (oper == NULL && proto != NULL) {
128 /* Not a system method, try the user protocol. */
129 oper = proto_get_oper(proto, method);
130 }
131
132 if (oper != NULL) {
133 printf("%s (%" PRIun ")", oper->name, method);
134 return;
135 }
136
137 printf("%" PRIun, method);
138}
139
140void ipcp_init(void)
141{
142 val_type_t arg_def[OPER_MAX_ARGS] = {
143 V_INTEGER,
144 V_INTEGER,
145 V_INTEGER,
146 V_INTEGER,
147 V_INTEGER
148 };
149
150 /*
151 * Create a pseudo-protocol 'unknown' that has no known methods.
152 */
153 proto_unknown = proto_new("unknown");
154
155 /*
156 * Create a pseudo-protocol 'system' defining names of system IPC
157 * methods.
158 */
159 proto_system = proto_new("system");
160
161 for (size_t i = 0; i < ipc_methods_len; i++) {
162 oper_t *oper = oper_new(ipc_methods[i].name, OPER_MAX_ARGS,
163 arg_def, V_INTEGER, OPER_MAX_ARGS, arg_def);
164 proto_add_oper(proto_system, ipc_methods[i].number, oper);
165 }
166
167 bool ok = hash_table_create(&pending_calls, 0, 0, &pending_call_ops);
168 assert(ok);
169}
170
171void ipcp_cleanup(void)
172{
173 proto_delete(proto_system);
174 hash_table_destroy(&pending_calls);
175}
176
177void ipcp_call_out(cap_phone_handle_t phandle, ipc_call_t *call,
178 cap_call_handle_t chandle)
179{
180 pending_call_t *pcall;
181 proto_t *proto;
182 oper_t *oper;
183 sysarg_t *args;
184 int i;
185
186 if (have_conn[cap_handle_raw(phandle)])
187 proto = connections[cap_handle_raw(phandle)].proto;
188 else
189 proto = NULL;
190
191 args = call->args;
192
193 if ((display_mask & DM_IPC) != 0) {
194 printf("Call handle: %p, phone: %p, proto: %s, method: ",
195 chandle, phandle, (proto ? proto->name : "n/a"));
196 ipc_m_print(proto, ipc_get_imethod(call));
197 printf(" args: (%" PRIun ", %" PRIun ", %" PRIun ", "
198 "%" PRIun ", %" PRIun ")\n",
199 args[1], args[2], args[3], args[4], args[5]);
200 }
201
202 if ((display_mask & DM_USER) != 0) {
203
204 if (proto != NULL) {
205 oper = proto_get_oper(proto, ipc_get_imethod(call));
206 } else {
207 oper = NULL;
208 }
209
210 if (oper != NULL) {
211
212 printf("%s(%p).%s", (proto ? proto->name : "n/a"),
213 phandle, (oper ? oper->name : "unknown"));
214
215 putchar('(');
216 for (i = 1; i <= oper->argc; ++i) {
217 if (i > 1)
218 printf(", ");
219 val_print(args[i], oper->arg_type[i - 1]);
220 }
221 putchar(')');
222
223 if (oper->rv_type == V_VOID && oper->respc == 0) {
224 /*
225 * No response data (typically the task will
226 * not be interested in the response).
227 * We will not display response.
228 */
229 putchar('.');
230 }
231
232 putchar('\n');
233 }
234 } else {
235 oper = NULL;
236 }
237
238 /* Store call in hash table for response matching */
239
240 pcall = malloc(sizeof(pending_call_t));
241 pcall->phone_handle = phandle;
242 pcall->question = *call;
243 pcall->call_handle = chandle;
244 pcall->oper = oper;
245
246 hash_table_insert(&pending_calls, &pcall->link);
247}
248
249static void parse_answer(cap_call_handle_t call_handle, pending_call_t *pcall,
250 ipc_call_t *answer)
251{
252 cap_phone_handle_t phone;
253 sysarg_t method;
254 sysarg_t service;
255 errno_t retval;
256 proto_t *proto;
257 cap_phone_handle_t cphone;
258
259 sysarg_t *resp;
260 oper_t *oper;
261 int i;
262
263 phone = pcall->phone_handle;
264 method = ipc_get_imethod(&pcall->question);
265 retval = ipc_get_retval(answer);
266
267 resp = answer->args;
268
269 if ((display_mask & DM_IPC) != 0) {
270 printf("Response to %p: retval=%s, args = (%" PRIun ", "
271 "%" PRIun ", %" PRIun ", %" PRIun ", %" PRIun ")\n",
272 call_handle, str_error_name(retval), ipc_get_arg1(answer),
273 ipc_get_arg2(answer), ipc_get_arg3(answer),
274 ipc_get_arg4(answer), ipc_get_arg5(answer));
275 }
276
277 if ((display_mask & DM_USER) != 0) {
278 oper = pcall->oper;
279
280 if ((oper != NULL) &&
281 ((oper->rv_type != V_VOID) || (oper->respc > 0))) {
282 printf("->");
283
284 if (oper->rv_type != V_VOID) {
285 putchar(' ');
286 val_print((sysarg_t) retval, oper->rv_type);
287 }
288
289 if (oper->respc > 0) {
290 putchar(' ');
291 putchar('(');
292 for (i = 1; i <= oper->respc; ++i) {
293 if (i > 1)
294 printf(", ");
295 val_print(resp[i], oper->resp_type[i - 1]);
296 }
297 putchar(')');
298 }
299
300 putchar('\n');
301 }
302 }
303
304 if ((phone == PHONE_NS) && (method == IPC_M_CONNECT_ME_TO) &&
305 (retval == 0)) {
306 /* Connected to a service (through NS) */
307 service = ipc_get_arg2(&pcall->question);
308 proto = proto_get_by_srv(service);
309 if (proto == NULL)
310 proto = proto_unknown;
311
312 cphone = (cap_phone_handle_t) ipc_get_arg5(answer);
313 if ((display_mask & DM_SYSTEM) != 0) {
314 printf("Registering connection (phone %p, protocol: %s)\n", cphone,
315 proto->name);
316 }
317
318 ipcp_connection_set(cphone, 0, proto);
319 }
320}
321
322void ipcp_call_in(ipc_call_t *call, cap_call_handle_t chandle)
323{
324 ht_link_t *item;
325 pending_call_t *pcall;
326
327 if ((call->flags & IPC_CALL_ANSWERED) == 0) {
328 /* Not a response */
329 if ((display_mask & DM_IPC) != 0) {
330 printf("Not a response (handle %p)\n", chandle);
331 }
332 return;
333 }
334
335 item = hash_table_find(&pending_calls, &chandle);
336 if (item == NULL)
337 return; /* No matching question found */
338
339 /*
340 * Response matched to question.
341 */
342
343 pcall = hash_table_get_inst(item, pending_call_t, link);
344 hash_table_remove(&pending_calls, &chandle);
345
346 parse_answer(chandle, pcall, call);
347 free(pcall);
348}
349
350void ipcp_hangup(cap_phone_handle_t phone, errno_t rc)
351{
352 if ((display_mask & DM_SYSTEM) != 0) {
353 printf("Hang up phone %p -> %s\n", phone, str_error_name(rc));
354 ipcp_connection_clear(phone);
355 }
356}
357
358/** @}
359 */
Note: See TracBrowser for help on using the repository browser.