1/** 2 * \file 3 * \brief Distops common server/client framework 4 */ 5 6/* 7 * Copyright (c) 2016, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <barrelfish/barrelfish.h> 16#include <barrelfish/nameservice_client.h> 17#include <if/test_defs.h> 18 19#include "test.h" 20 21static const char *service_name = "distops_test"; 22 23//{{{1 Generic testing function for retype 24void test_retype(struct capref src, struct capref *dest, gensize_t offset, 25 gensize_t size, size_t count, errval_t expected_err, const char *role) 26{ 27 errval_t err; 28 struct capref result = NULL_CAP; 29 bool free = false; 30 31 if (!dest) { 32 dest = &result; 33 free = true; 34 } 35 36 if (capref_is_null(*dest)) { 37 if (count != 1) { 38 USER_PANIC("%s_%s: did not provide capref, but more than one object requested", 39 role, __FUNCTION__); 40 } 41 err = slot_alloc(dest); 42 PANIC_IF_ERR(err, "in %s: slot_alloc for retype result", role); 43 } 44 45 // Tests come here 46 err = cap_retype(*dest, src, offset, ObjType_Frame, size, count); 47 if (err != expected_err) { 48 printf("distops_retype: retype(offset=%"PRIuGENSIZE", size=%"PRIuGENSIZE 49 ", count=%zu) to Frame returned %s, expected %s\n", 50 offset, size, count, err_getcode(err), err_getcode(expected_err)); 51 } 52 if (free) { 53 if (err_is_ok(err)) { 54 // Cap delete only necessary if retype successful 55 err = cap_delete(result); 56 PANIC_IF_ERR(err, "cap_delete in %s_test_retype", role); 57 } 58 err = slot_free(result); 59 PANIC_IF_ERR(err, "slot_free in %s_test_retype", role); 60 } 61} 62 63//{{{1 Unused message handlers 64static void rx_str(struct test_binding *b, uint32_t arg, const char *s) 65{ 66 printf("rx_str %"PRIu32" '%s'\n", arg, s); 67} 68 69static void rx_buf(struct test_binding *b, const uint8_t *buf, size_t buflen) 70{ 71 printf("rx_buf buflen=%zu\n", buflen); 72} 73 74//{{{1 Server 75 76//{{{2 Server-side message handlers 77 78static void server_rx_basic(struct test_binding *b, uint32_t arg) 79{ 80 printf("server rx_basic %"PRIu32"\n", arg); 81 server_do_test(b, arg, NULL_CAP); 82} 83 84static void server_rx_caps(struct test_binding *b, uint32_t arg, struct capref cap1, 85 struct capref cap2) 86{ 87 server_do_test(b, arg, cap1); 88} 89 90static struct test_rx_vtbl server_rx_vtbl = { 91 .basic = server_rx_basic, 92 .str = rx_str, 93 .caps = server_rx_caps, 94 .buf = rx_buf, 95}; 96 97// {{{2 Server export & connect 98 99static void export_cb(void *st, errval_t err, iref_t iref) 100{ 101 PANIC_IF_ERR(err, "export failed"); 102 103 printf("service exported at iref %"PRIuIREF"\n", iref); 104 105 // register this iref with the name service 106 err = nameservice_register(service_name, iref); 107 PANIC_IF_ERR(err, "nameservice_register failed"); 108} 109 110static errval_t connect_cb(void *st, struct test_binding *b) 111{ 112 printf("service got a connection!\n"); 113 114 // copy my message receive handler vtable to the binding 115 b->rx_vtbl = server_rx_vtbl; 116 117 // Create a server state struct for this connection 118 init_server(b); 119 120 // accept the connection (we could return an error to refuse it) 121 return SYS_ERR_OK; 122} 123 124static void run_server(void) 125{ 126 errval_t err; 127 128 err = test_export(NULL /* state pointer for connect/export callbacks */, 129 export_cb, connect_cb, get_default_waitset(), 130 IDC_EXPORT_FLAGS_DEFAULT); 131 PANIC_IF_ERR(err, "export failed"); 132} 133//{{{1 Client 134 135//{{{2 Client-side message handlers 136 137// We use test.basic to signal that server has done it's retypes 138static void client_rx_basic(struct test_binding *b, uint32_t arg) 139{ 140 printf("client rx_basic %"PRIu32": b->st = %p\n", arg, b->st); 141 142 client_do_test(b, arg, NULL_CAP); 143} 144 145static void client_rx_caps(struct test_binding *b, uint32_t arg, struct capref cap1, 146 struct capref cap2) 147{ 148 printf("client rx_caps: arg=%"PRIu32"\n", arg); 149 cap_destroy(cap1); 150 cap_destroy(cap2); 151} 152 153static struct test_rx_vtbl client_rx_vtbl = { 154 .basic = client_rx_basic, 155 .str = rx_str, 156 .caps = client_rx_caps, 157 .buf = rx_buf, 158}; 159 160//{{{2 Client bind 161 162static void bind_cb(void *st, errval_t err, struct test_binding *b) 163{ 164 PANIC_IF_ERR(err, "bind failed"); 165 166 printf("client bound!\n"); 167 168 // copy my message receive handler vtable to the binding 169 b->rx_vtbl = client_rx_vtbl; 170 171 // Initialize client side 172 init_client(b); 173} 174 175static void run_client(void) 176{ 177 errval_t err; 178 iref_t iref; 179 180 printf("client looking up '%s' in name service...\n", service_name); 181 err = nameservice_blocking_lookup(service_name, &iref); 182 PANIC_IF_ERR(err, "nameservice_blocking_lookup failed"); 183 184 printf("client binding to %"PRIuIREF"...\n", iref); 185 186 err = test_bind(iref, bind_cb, NULL, get_default_waitset(), IDC_BIND_FLAGS_DEFAULT); 187 PANIC_IF_ERR(err, "bind failed"); 188} 189 190//{{{1 Main 191int main(int argc, char *argv[]) 192{ 193 char *role; 194 if (argc < 2) { 195 printf("remote retype test needs an argument of \"server\" or \"client\"\n"); 196 } 197 if (strncmp(argv[1], "server", 6) == 0) { 198 printf("we are the server\n"); 199 role = "server"; 200 run_server(); 201 } 202 if (strncmp(argv[1], "client", 6) == 0) { 203 printf("we are the client\n"); 204 role = "client"; 205 run_client(); 206 } 207 208 errval_t err; 209 struct waitset *ws = get_default_waitset(); 210 while (true) { 211 err = event_dispatch(ws); 212 PANIC_IF_ERR(err, "in %s: event_dispatch", role); 213 } 214 215 return 0; 216} 217