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