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