1/** \file 2 * \brief RPC system test code 3 */ 4 5/* 6 * Copyright (c) 2010, ETH Zurich. 7 * All rights reserved. 8 * 9 * This file is distributed under the terms in the attached LICENSE file. 10 * If you do not find this file, copies can be found by writing to: 11 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 12 */ 13 14#include <string.h> 15#include <stdio.h> 16#include <stdarg.h> 17#include <barrelfish/barrelfish.h> 18#include <barrelfish/nameservice_client.h> 19 20#include <if/test_rpc_cap_defs.h> 21#include <if/test_rpc_cap_defs.h> 22 23static const char *my_service_name = "rpc_cap_test"; 24uint8_t is_server = 0x0; 25int client_id = 0; 26 27__attribute__((format(printf, 1, 2))) 28static void my_debug_printf(const char *fmt, ...) 29{ 30 struct thread *me = thread_self(); 31 va_list argptr; 32 char id[32] = "-"; 33 char str[1024]; 34 size_t len; 35 36 if (me) 37 snprintf(id, sizeof(id), "%"PRIuPTR, thread_get_id(me)); 38 len = snprintf(str, sizeof(str), "\033[34m%.*s.\033[31m%u.%s\033[0m: ", 39 DISP_NAME_LEN, disp_name(), disp_get_core_id(), id); 40 41 if(is_server){ 42 len += snprintf(str + len, sizeof(str) - len, "server: "); 43 } else { 44 len += snprintf(str + len, sizeof(str) - len, "client(%d): ", 45 client_id); 46 } 47 48 if (len < sizeof(str)) { 49 va_start(argptr, fmt); 50 vsnprintf(str + len, sizeof(str) - len, fmt, argptr); 51 va_end(argptr); 52 } 53 sys_print(str, sizeof(str)); 54} 55 56 57 58struct echo_response { 59 struct test_rpc_cap_binding *b; 60 uint32_t response; 61}; 62 63static void send_echo_response(void *arg){ 64 struct echo_response * resp = arg; 65 errval_t err; 66 err = test_rpc_cap_echo_response__tx(resp->b, NOP_CONT, resp->response); 67 assert(err_is_ok(err)); 68} 69 70 71static void handle_echo_call(struct test_rpc_cap_binding *b, 72 uint32_t arg_in) 73{ 74 my_debug_printf("handle_echo_call (bind=%p) arg=%"PRIu32"\n", b, arg_in); 75 struct echo_response * resp = malloc(sizeof(*resp)); 76 resp->b = b; 77 resp->response = arg_in; 78 send_echo_response(resp); 79} 80 81 82static void handle_send_cap_one_call(struct test_rpc_cap_binding *b, 83 struct capref incap) 84{ 85 my_debug_printf("handle_send_cap_one_call (bind=%p)\n", b); 86 errval_t err = SYS_ERR_OK; 87 struct capability cap; 88 err = debug_cap_identify(incap, &cap ); 89 90 test_rpc_cap_send_cap_one_response__tx(b, NOP_CONT, err); 91} 92 93static void handle_send_cap_two_call(struct test_rpc_cap_binding *b, 94 struct capref incap1, struct capref incap2) 95{ 96 my_debug_printf("handle_send_cap_two_call (bind=%p)\n", b); 97 errval_t err = SYS_ERR_OK; 98 struct capability cap; 99 100 err = debug_cap_identify(incap1, &cap); 101 assert(err_is_ok(err)); 102 err = debug_cap_identify(incap2, &cap); 103 assert(err_is_ok(err)); 104 105 test_rpc_cap_send_cap_two_response__tx(b, NOP_CONT, err); 106} 107 108static struct test_rpc_cap_rx_vtbl rx_vtbl = { 109 .echo_call = handle_echo_call, 110 .send_cap_one_call = handle_send_cap_one_call, 111 .send_cap_two_call = handle_send_cap_two_call 112}; 113 114/* ------------------------------ CLIENT ------------------------------ */ 115 116static struct test_rpc_cap_binding *test_rpc_binding; 117 118static void client_call_test_1(void){ 119 uint32_t res=0; 120 errval_t err; 121 err = test_rpc_binding->rpc_tx_vtbl.echo(test_rpc_binding, client_id, &res); 122 if(err_is_fail(err)){ 123 my_debug_printf("Error in rpc call (1)\n"); 124 } else if(res != client_id) { 125 my_debug_printf("Wrong result?\n"); 126 } else { 127 my_debug_printf("client_call_test_1 successful!\n"); 128 } 129} 130 131static void client_call_test_2(void){ 132 struct capref my_frame; 133 errval_t err, msg_err; 134 135 err = frame_alloc(&my_frame, BASE_PAGE_SIZE, NULL); 136 assert(err_is_ok(err)); 137 138 err = test_rpc_binding->rpc_tx_vtbl.send_cap_one(test_rpc_binding, my_frame, &msg_err); 139 if(err_is_fail(err)){ 140 USER_PANIC_ERR(err, "Error in rpc call (2)\n"); 141 } else if(err_is_fail(msg_err)) { 142 USER_PANIC_ERR(err, "Server msg (2)\n"); 143 } else { 144 my_debug_printf("client_call_test_2 successful!\n"); 145 } 146} 147 148static void client_call_test_3(int i){ 149 struct capref frame1, frame2; 150 struct capability cap1, cap2; 151 char buf[1024]; 152 int buf_idx=0; 153 errval_t err, msg_err; 154 155 err = frame_alloc(&frame1, BASE_PAGE_SIZE, NULL); 156 assert(err_is_ok(err)); 157 err = debug_cap_identify(frame1, &cap1); 158 assert(err_is_ok(err)); 159 buf_idx += debug_print_cap(buf, sizeof(buf), &cap1); 160 161 err = frame_alloc(&frame2, BASE_PAGE_SIZE, NULL); 162 assert(err_is_ok(err)); 163 err = debug_cap_identify(frame2, &cap2); 164 assert(err_is_ok(err)); 165 buf_idx += debug_print_cap(buf+buf_idx, sizeof(buf)-buf_idx, &cap2); 166 167 my_debug_printf("Calling send_cap_two: %s\n", buf); 168 169 err = test_rpc_binding->rpc_tx_vtbl.send_cap_two(test_rpc_binding, frame1, frame2, &msg_err); 170 if(err_is_fail(err)){ 171 USER_PANIC_ERR(err, "Error in rpc call (3)\n"); 172 } else if(err_is_fail(msg_err)) { 173 USER_PANIC_ERR(err, "Server msg (3)\n"); 174 } else { 175 my_debug_printf("client_call_test_3(%d) successful!\n", i); 176 } 177} 178 179static void bind_cb(void *st, 180 errval_t err, 181 struct test_rpc_cap_binding *b) 182{ 183 if (err_is_fail(err)) { 184 USER_PANIC_ERR(err, "bind failed"); 185 } 186 187 my_debug_printf("client: bound!\n"); 188 189 test_rpc_binding = b; 190 test_rpc_cap_rpc_client_init(b); 191 192 client_call_test_1(); 193 client_call_test_2(); 194 for(int i=0; i<100;i++){ 195 client_call_test_3(i); 196 } 197 printf("TEST PASSED\n"); 198} 199 200static void start_client(void) 201{ 202 iref_t iref; 203 errval_t err; 204 205 my_debug_printf("client: looking up '%s' in name service...\n", my_service_name); 206 err = nameservice_blocking_lookup(my_service_name, &iref); 207 if (err_is_fail(err)) { 208 USER_PANIC_ERR(err, "nameservice_blocking_lookup failed"); 209 } 210 211 my_debug_printf("client: binding to %"PRIuIREF"...\n", iref); 212 err = test_rpc_cap_bind(iref, bind_cb, NULL , 213 get_default_waitset(), 214 IDC_BIND_FLAGS_DEFAULT); 215 if (err_is_fail(err)) { 216 USER_PANIC_ERR(err, "bind failed"); 217 } 218} 219 220/* ------------------------------ SERVER ------------------------------ */ 221 222 223static void export_cb(void *st, 224 errval_t err, 225 iref_t iref) 226{ 227 if (err_is_fail(err)) { 228 USER_PANIC_ERR(err, "export failed"); 229 } 230 231 // register this iref with the name service 232 err = nameservice_register(my_service_name, iref); 233 if (err_is_fail(err)) { 234 USER_PANIC_ERR(err, "nameservice_register failed"); 235 } 236 237 my_debug_printf("server: service %s exported at iref %"PRIuIREF"\n", my_service_name, iref); 238} 239 240static errval_t connect_cb(void *st, 241 struct test_rpc_cap_binding *b) 242{ 243 my_debug_printf("server: client connected!\n"); 244 245 // copy my message receive handler vtable to the binding 246 b->rx_vtbl = rx_vtbl; 247 248 // accept the connection (we could return an error to refuse it) 249 return SYS_ERR_OK; 250} 251 252static void start_server(void) 253{ 254 errval_t err; 255 256 my_debug_printf("server: Starting server...\n"); 257 258 is_server = 0x1; 259 260 err = test_rpc_cap_export(NULL, 261 export_cb, 262 connect_cb, 263 get_default_waitset(), 264 IDC_EXPORT_FLAGS_DEFAULT); 265 if (err_is_fail(err)) { 266 USER_PANIC_ERR(err, "export failed"); 267 } 268} 269 270/* ------------------------------ MAIN ------------------------------ */ 271 272static int usage(char * argv[]){ 273 printf("Usage: %s client|server [id=INT]\n", argv[0]); 274 return EXIT_FAILURE; 275} 276 277int main(int argc, 278 char *argv[]) 279{ 280 errval_t err; 281 282 if (argc >= 2 && strcmp(argv[1], "client") == 0) { 283 for(int i = 2; i < argc; i++){ 284 if(strncmp(argv[i], "id=", strlen("id=")) == 0){ 285 client_id = atoi(argv[i] + 3); 286 } else { 287 printf("Unknonw argument: %s\n", argv[i]); 288 return usage(argv); 289 } 290 } 291 start_client(); 292 } else if (argc == 2 && strcmp(argv[1], "server") == 0) { 293 start_server(); 294 } else { 295 return usage(argv); 296 } 297 298 struct waitset *ws = get_default_waitset(); 299 while (1) { 300 err = event_dispatch(ws); 301 if (err_is_fail(err)) { 302 DEBUG_ERR(err, "in event_dispatch"); 303 break; 304 } 305 } 306 307 return EXIT_FAILURE; 308} 309