1/** \file
2 *  \brief Example rpc application using call/response stubs
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#include <stdio.h>
15#include <string.h>
16
17#include <barrelfish/barrelfish.h>
18#include <barrelfish/nameservice_client.h>
19
20#include <if/xmplrpc_defs.h>
21
22const char *service_name = "xmplrpc_msg_service";
23
24/* --------------------- Client ------------------------------ */
25
26static void rx_myrpc_response(struct xmplrpc_binding *b, const char *s)
27{
28    debug_printf("client: rx_myrpc_response called: %s\n", s);
29
30    // no need to free s
31}
32
33
34static void send_myrpc_call_cb(void *a)
35{
36    debug_printf("client: myrpc_call sent successfully\n");
37}
38
39static void send_myrpc_call(void *a)
40{
41    errval_t err;
42
43    debug_printf("client: sending mycall\n");
44
45    struct xmplrpc_binding *b = (struct xmplrpc_binding *)a;
46
47    struct event_closure txcont = MKCONT(send_myrpc_call_cb, b);
48
49    err = xmplrpc_myrpc_call__tx(b, txcont, 42);
50
51    if (err_is_fail(err)) {
52        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
53            debug_printf("client: re-sending mycall\n");
54            struct waitset *ws = get_default_waitset();
55	    txcont = MKCONT(send_myrpc_call, b);
56            err = b->register_send(b, ws, txcont);
57            if (err_is_fail(err)) {
58                // note that only one continuation may be registered at a time
59                DEBUG_ERR(err, "register_send on binding failed!");
60            }
61        } else {
62            DEBUG_ERR(err, "error sending mycall message\n");
63        }
64    }
65}
66
67struct xmplrpc_rx_vtbl c_rx_vtbl = {
68    .myrpc_response = rx_myrpc_response,
69};
70
71static void bind_cb(void *st, errval_t err, struct xmplrpc_binding *b)
72{
73    if (err_is_fail(err)) {
74        USER_PANIC_ERR(err, "bind failed");
75    }
76
77    b->rx_vtbl = c_rx_vtbl;
78
79    send_myrpc_call(b);
80}
81
82
83static void start_client(void)
84{
85    errval_t err;
86    iref_t iref;
87
88    err = nameservice_blocking_lookup(service_name, &iref);
89    if (err_is_fail(err)) {
90        USER_PANIC_ERR(err, "nameservice_blocking_lookup failed");
91    }
92
93    err = xmplrpc_bind(iref,
94                     bind_cb,
95                     NULL /* state for bind_cb */,
96                     get_default_waitset(),
97                     IDC_BIND_FLAGS_DEFAULT);
98    if (err_is_fail(err)) {
99        USER_PANIC_ERR(err, "bind failed");
100    }
101}
102
103/* --------------------- Server ------------------------------ */
104
105struct server_state {
106    struct xmplrpc_binding *b;
107    char *s;
108};
109
110static void free_st(struct server_state* st)
111{
112    if (st->s != NULL) free(st->s);
113    free(st);
114}
115
116static void send_myrpc_response_cb(void *a)
117{
118    struct server_state *st = (struct server_state*)a;
119
120    debug_printf("server: myresponse sent succesfully\n");
121
122    free_st(st);
123}
124
125static void send_myrpc_response(void *a)
126{
127    errval_t err;
128    struct server_state *st = (struct server_state*)a;
129
130    debug_printf("server: sending myresponse\n");
131
132    struct event_closure txcont = MKCONT(send_myrpc_response_cb, st);
133    err = xmplrpc_myrpc_response__tx(st->b, txcont, st->s);
134
135    if (err_is_fail(err)) {
136        if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
137            debug_printf("server: re-sending myresponse\n");
138            struct waitset *ws = get_default_waitset();
139            txcont = MKCONT(send_myrpc_response, st);
140            err = st->b->register_send(st->b, ws, txcont);
141            if (err_is_fail(err)) {
142                // note that only one continuation may be registered at a time
143                DEBUG_ERR(err, "register_send on binding failed!");
144                free_st(st);
145            }
146        } else {
147            DEBUG_ERR(err, "error sending mycall message\n");
148            free_st(st);
149        }
150    }
151}
152
153static void rx_myrpc_call(struct xmplrpc_binding *b, int i)
154{
155    debug_printf("server: received myrpc_call: %d\n", i);
156
157    // prepare and send reply
158
159    struct server_state *st = malloc(sizeof(struct server_state));
160    if (st == NULL) {
161        USER_PANIC("cannot reply, out of memory");
162    }
163
164    st->b = b;
165    st->s = malloc(20);
166    if (st->s != NULL) {
167        snprintf(st->s, 20, "!%d!", i);
168    }
169
170    send_myrpc_response(st);
171}
172
173static struct xmplrpc_rx_vtbl s_rx_vtbl = {
174    .myrpc_call = rx_myrpc_call,
175};
176
177static errval_t connect_cb(void *st, struct xmplrpc_binding *b)
178{
179    b->rx_vtbl = s_rx_vtbl;
180
181    return SYS_ERR_OK;
182}
183
184static void export_cb(void *st, errval_t err, iref_t iref)
185{
186    if (err_is_fail(err)) {
187        USER_PANIC_ERR(err, "export failed");
188    }
189
190    err = nameservice_register(service_name, iref);
191    if (err_is_fail(err)) {
192        USER_PANIC_ERR(err, "nameservice_register failed");
193    }
194}
195
196static void start_server(void)
197{
198    errval_t err;
199
200    err = xmplrpc_export(NULL /* state pointer for connect/export callbacks */,
201                        export_cb, connect_cb,
202                        get_default_waitset(),
203                        IDC_EXPORT_FLAGS_DEFAULT);
204    if (err_is_fail(err)) {
205        USER_PANIC_ERR(err, "export failed");
206    }
207}
208
209
210
211/* --------------------- Main ------------------------------ */
212
213int main(int argc, char *argv[])
214{
215    errval_t err;
216
217    if ((argc >= 2) && (strcmp(argv[1], "client") == 0)) {
218        start_client();
219    } else if ((argc >= 2) && (strcmp(argv[1], "server") == 0)) {
220        start_server();
221    } else {
222        printf("usage: %s client|server\n", argv[0]);
223        return EXIT_FAILURE;
224    }
225
226    struct waitset *ws = get_default_waitset();
227    while (1) {
228        err = event_dispatch(ws);
229        if (err_is_fail(err)) {
230            DEBUG_ERR(err, "in event_dispatch");
231            break;
232        }
233    }
234
235    return EXIT_FAILURE;
236}
237