1/** \file 2 * \brief IDC 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 12 */ 13 14#define _USE_XOPEN /* for strdup() */ 15#include <string.h> 16#include <stdio.h> 17#include <barrelfish/barrelfish.h> 18#include <barrelfish/nameservice_client.h> 19#include <barrelfish/debug.h> 20#include <barrelfish/deferred.h> 21#include <if/test_defs.h> 22 23static const char *my_service_name = "idctest"; 24 25static const char *longstr = "" 26 "Far out in the uncharted backwaters of the unfashionable end of the\n" 27 "western spiral arm of the Galaxy lies a small unregarded yellow sun.\n" 28 "\n" 29 "Orbiting this at a distance of roughly ninety-two million miles is an\n" 30 "utterly insignificant little blue green planet whose ape- descended life\n" 31 "forms are so amazingly primitive that they still think digital watches\n" 32 "are a pretty neat idea.\n" 33 "\n" 34 "This planet has - or rather had - a problem, which was this: most of the\n" 35 "people on it were unhappy for pretty much of the time. Many solutions\n" 36 "were suggested for this problem, but most of these were largely concerned\n" 37 "with the movements of small green pieces of paper, which is odd because\n" 38 "on the whole it wasn't the small green pieces of paper that were unhappy.\n" 39 "\n" 40 "And so the problem remained; lots of the people were mean, and most\n" 41 "of them were miserable, even the ones with digital watches.\n" 42 "\n" 43 "Many were increasingly of the opinion that they'd all made a big mistake\n" 44 "in coming down from the trees in the first place. And some said that\n" 45 "even the trees had been a bad move, and that no one should ever have\n" 46 "left the oceans.\n" 47 "\n" 48 "And then, one Thursday, nearly two thousand years after one man had\n" 49 "been nailed to a tree for saying how great it would be to be nice to people\n" 50 "for a change, one girl sitting on her own in a small cafe in Rickmansworth\n" 51 "suddenly realized what it was that had been going wrong all this time,\n" 52 "and she finally knew how the world could be made a good and happy\n" 53 "place. This time it was right, it would work, and no one would have to\n" 54 "get nailed to anything.\n" 55 "\n" 56 "Sadly, however, before she could get to a phone to tell anyone- about it,\n" 57 "a terribly stupid catastrophe occurred, and the idea was lost forever.\n" 58 "\n" 59 "This is her story."; 60 61static const char *shortstr = "Hello, world!"; 62 63/* ------------------------ COMMON MESSAGE HANDLERS ------------------------ */ 64 65static void rx_basic(struct test_binding *b, uint32_t arg) 66{ 67 debug_printf("rx_basic %"PRIu32"\n", arg); 68 assert(arg == 7); 69} 70 71static void rx_str(struct test_binding *b, uint32_t arg, const char *s) 72{ 73 debug_printf("rx_str %"PRIu32" Str[:5]:'%.5s'\n", arg, s); 74 switch(arg){ 75 case 9: 76 case 37: 77 assert(strcmp(shortstr, s) == 0); 78 break; 79 case 42: 80 assert(strcmp(longstr, s) == 0); 81 break; 82 default: 83 assert(!"wrong argument received!"); 84 } 85} 86 87static void rx_one_cap(struct test_binding *b, uint32_t arg, 88 struct capref cap1) 89{ 90 char buf1[256]; 91 debug_print_cap_at_capref(buf1, sizeof(buf1), cap1); 92 buf1[sizeof(buf1) - 1] = '\0'; 93 debug_printf("rx_one_cap %"PRIu32" [%s]\n", arg, buf1); 94} 95 96static void rx_caps(struct test_binding *b, uint32_t arg, 97 struct capref cap1, struct capref cap2) 98{ 99 char buf1[256], buf2[256]; 100 debug_print_cap_at_capref(buf1, sizeof(buf1), cap1); 101 debug_print_cap_at_capref(buf2, sizeof(buf2), cap2); 102 buf1[sizeof(buf1) - 1] = '\0'; 103 buf2[sizeof(buf2) - 1] = '\0'; 104 debug_printf("rx_caps %"PRIu32" [%s] [%s]\n", arg, buf1, buf2); 105} 106 107static void rx_buf(struct test_binding *b, const uint8_t *buf, size_t buflen) 108{ 109 debug_printf("rx_buf (%zu bytes)\n", buflen); 110} 111 112static struct test_rx_vtbl rx_vtbl = { 113 .basic = rx_basic, 114 .str = rx_str, 115 .one_cap = rx_one_cap, 116 .caps = rx_caps, 117 .buf = rx_buf, 118}; 119 120/* ------------------------------ CLIENT ------------------------------ */ 121 122struct client_state { 123 struct test_binding *binding; 124 int nextmsg; 125 char *str; 126 struct capref cap1, cap2, cap3; 127}; 128 129// send the next message in our sequence 130static void send_cont(void *arg) 131{ 132 struct client_state *myst = arg; 133 struct test_binding *b = myst->binding; 134 struct event_closure txcont = MKCONT(send_cont, myst); 135 errval_t err = SYS_ERR_OK; 136 137 debug_printf("client sending msg %d\n", myst->nextmsg); 138 139 switch(myst->nextmsg) { 140 case 0: 141 err = test_basic__tx(b, txcont, 7); 142 break; 143 144 case 1: 145 // send a static string 146 err = test_str__tx(b, txcont, 9, shortstr); 147 break; 148 149 case 2: 150 // send a "dynamically allocated" string 151 myst->str = strdup(shortstr); 152 err = test_str__tx(b, txcont, 37, myst->str); 153 break; 154 155 case 3: 156 // deallocate the string we sent in the previous message 157 free(myst->str); 158 159 // send a long string 160 err = test_str__tx(b, txcont, 42, longstr); 161 break; 162 163 case 4: 164 err = frame_alloc(&myst->cap1, BASE_PAGE_SIZE, NULL); 165 assert(err_is_ok(err)); 166 err = test_one_cap__tx(b, txcont, 77, myst->cap1); 167 break; 168 169 case 5: 170 // create some caps to send (assume it all works) 171 err = frame_alloc(&myst->cap2, BASE_PAGE_SIZE, NULL); 172 assert(err_is_ok(err)); 173 174 err = slot_alloc(&myst->cap3); 175 assert(err_is_ok(err)); 176 177 err = vnode_create(myst->cap3, ObjType_VNode_x86_64_ptable); 178 assert(err_is_ok(err)); 179 180 err = test_caps__tx(b, txcont, 69, myst->cap2, myst->cap3); 181 break; 182 183 case 6: 184 // delete the caps, now they've been sent 185 //err = cap_destroy(myst->cap1); 186 //assert(err_is_ok(err)); 187 188 //err = cap_destroy(myst->cap2); 189 //assert(err_is_ok(err)); 190 191 // send a "buffer" 192 err = test_buf__tx(b, txcont, (uint8_t *)longstr, strlen(longstr)); 193 break; 194 195 case 7: 196 // here is where we would deallocate the buffer, if it wasn't static 197 // client all done is the message determined to terminate the test, 198 // wait a bit to give the server time to print the message. 199 barrelfish_usleep(1000000); 200 printf("client all done!\n"); 201 return; 202 203 default: 204 err = LIB_ERR_NOT_IMPLEMENTED; // TODO: Make meaningful 205 assert(!"shouldn't happen"); 206 } 207 208 if (err_is_ok(err)) { 209 myst->nextmsg++; 210 } else { 211 DEBUG_ERR(err, "error sending message %d", myst->nextmsg); 212 213 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 214 assert(!"binding is busy for tx?!"); 215 216 // this error should never happen to us, because we serialise all 217 // sends with the continuation, however it may happen in another 218 // situation if the binding is already busy sending. in this case, 219 // the user can use something like: 220 221 struct waitset *ws = get_default_waitset(); 222 err = b->register_send(b, ws, txcont); 223 if (err_is_fail(err)) { 224 // note that only one continuation may be registered at a time 225 DEBUG_ERR(err, "register_send on binding failed!"); 226 } 227 } 228 229 abort(); 230 } 231} 232 233static void bind_cb(void *st, errval_t err, struct test_binding *b) 234{ 235 if (err_is_fail(err)) { 236 USER_PANIC_ERR(err, "bind failed"); 237 } 238 239 debug_printf("client bound!\n"); 240 241 // copy my message receive handler vtable to the binding 242 b->rx_vtbl = rx_vtbl; 243 244 // construct local per-binding state 245 struct client_state *myst = malloc(sizeof(struct client_state)); 246 assert(myst != NULL); 247 myst->nextmsg = 0; 248 myst->binding = b; 249 b->st = myst; 250 251 // start sending stuff to the service 252 send_cont(myst); 253} 254 255static void start_client(void) 256{ 257 iref_t iref; 258 errval_t err; 259 260 debug_printf("client looking up '%s' in name service...\n", my_service_name); 261 err = nameservice_blocking_lookup(my_service_name, &iref); 262 if (err_is_fail(err)) { 263 USER_PANIC_ERR(err, "nameservice_blocking_lookup failed"); 264 } 265 266 debug_printf("client binding to %"PRIuIREF"...\n", iref); 267 err = test_bind(iref, bind_cb, NULL /* state pointer for bind_cb */, 268 get_default_waitset(), IDC_BIND_FLAGS_DEFAULT); 269 if (err_is_fail(err)) { 270 USER_PANIC_ERR(err, "bind failed"); 271 } 272} 273 274/* ------------------------------ SERVER ------------------------------ */ 275 276static void export_cb(void *st, errval_t err, iref_t iref) 277{ 278 if (err_is_fail(err)) { 279 USER_PANIC_ERR(err, "export failed"); 280 } 281 282 debug_printf("service exported at iref %"PRIuIREF"\n", iref); 283 284 // register this iref with the name service 285 err = nameservice_register(my_service_name, iref); 286 if (err_is_fail(err)) { 287 USER_PANIC_ERR(err, "nameservice_register failed"); 288 } 289} 290 291static errval_t connect_cb(void *st, struct test_binding *b) 292{ 293 debug_printf("service got a connection!\n"); 294 295 // copy my message receive handler vtable to the binding 296 b->rx_vtbl = rx_vtbl; 297 298 // accept the connection (we could return an error to refuse it) 299 return SYS_ERR_OK; 300} 301 302static void start_server(void) 303{ 304 errval_t err; 305 306 err = test_export(NULL /* state pointer for connect/export callbacks */, 307 export_cb, connect_cb, get_default_waitset(), 308 IDC_EXPORT_FLAGS_DEFAULT); 309 if (err_is_fail(err)) { 310 USER_PANIC_ERR(err, "export failed"); 311 } 312} 313 314/* ------------------------------ MAIN ------------------------------ */ 315 316int main(int argc, char *argv[]) 317{ 318 errval_t err; 319 320 if (argc == 2 && strcmp(argv[1], "client") == 0) { 321 start_client(); 322 } else if (argc == 2 && strcmp(argv[1], "server") == 0) { 323 start_server(); 324 } else { 325 debug_printf("Usage: %s client|server\n", argv[0]); 326 return EXIT_FAILURE; 327 } 328 329 struct waitset *ws = get_default_waitset(); 330 while (1) { 331 err = event_dispatch(ws); 332 if (err_is_fail(err)) { 333 DEBUG_ERR(err, "in event_dispatch"); 334 break; 335 } 336 } 337 338 return EXIT_FAILURE; 339} 340