3 /* rpc - demo of the RPC features in GRAS */
5 /* Copyright (c) 2006 Martin Quinson. All rights reserved. */
7 /* This program is free software; you can redistribute it and/or modify it
8 * under the terms of the license (GNU LGPL) which comes with this package. */
12 XBT_LOG_NEW_DEFAULT_CATEGORY(Rpc, "Messages specific to this example");
14 /* register messages which may be sent (common to client and server) */
15 static void register_messages(void)
17 gras_msgtype_declare_rpc("plain ping",
18 gras_datadesc_by_name("int"),
19 gras_datadesc_by_name("int"));
21 gras_msgtype_declare_rpc("raise exception", NULL, NULL);
22 gras_msgtype_declare_rpc("forward exception", NULL, NULL);
23 gras_msgtype_declare("kill", NULL);
26 /* Function prototypes */
27 int server(int argc, char *argv[]);
28 int forwarder(int argc, char *argv[]);
29 int client(int argc, char *argv[]);
31 #define exception_msg "Error for the client"
32 #define exception_raising() THROW0(unknown_error,42,exception_msg)
34 static void exception_catching(void)
39 for (i = 0; i < 5; i++) {
48 THROW0(unknown_error, 0, "Didn't got the remote exception!");
50 xbt_assert2(e.category == unknown_error,
51 "Got wrong category: %d (instead of %d)", e.category,
53 xbt_assert1(e.value == 42, "Got wrong value: %d (!=42)", e.value);
54 xbt_assert1(!strncmp(e.msg, exception_msg, strlen(exception_msg)),
55 "Got wrong message: %s", e.msg);
60 /* **********************************************************************
62 * **********************************************************************/
65 int client(int argc, char *argv[])
68 gras_socket_t toserver = NULL; /* peer */
69 gras_socket_t toforwarder = NULL; /* peer */
72 volatile int gotit = 0;
75 const char *host = "127.0.0.1";
78 memset(&e, 0, sizeof(xbt_ex_t));
80 /* 1. Init the GRAS's infrastructure */
81 gras_init(&argc, argv);
83 /* 2. Get the server's address. The command line override defaults when specified */
88 INFO2("Launch client (server on %s:%d)", host, port);
92 /* 3. Wait for the server & forwarder startup */
95 /* 4. Create a socket to speak to the server */
98 toserver = gras_socket_client(host, port);
99 toforwarder = gras_socket_client(argv[3], atoi(argv[4]));
102 RETHROW0("Unable to connect to the server: %s");
104 INFO2("Connected to %s:%d.", host, port);
107 /* 5. Register the messages.
108 See, it doesn't have to be done completely at the beginning,
109 but only before use */
110 exception_catching();
113 /* 6. Keep the user informed of what's going on */
114 INFO2("Connected to server which is on %s:%d",
115 gras_socket_peer_name(toserver), gras_socket_peer_port(toserver));
117 /* 7. Prepare and send the ping message to the server */
120 exception_catching();
121 gras_msg_rpccall(toserver, 6000.0, "plain ping", &ping, &pong);
124 gras_socket_close(toserver);
125 RETHROW0("Failed to execute a PING rpc on the server: %s");
127 exception_catching();
129 /* 8. Keep the user informed of what's going on, again */
130 INFO4("The answer to PING(%d) on %s:%d is PONG(%d)",
132 gras_socket_peer_name(toserver), gras_socket_peer_port(toserver),
135 /* 9. Call a RPC which raises an exception (to test exception propagation) */
136 INFO0("Call the exception raising RPC");
138 gras_msg_rpccall(toserver, 6000.0, "raise exception", NULL, NULL);
142 xbt_assert2(e.category == unknown_error,
143 "Got wrong category: %d (instead of %d)",
144 e.category, unknown_error);
145 xbt_assert1(e.value == 42, "Got wrong value: %d (!=42)", e.value);
146 xbt_assert1(!strncmp(e.msg, exception_msg, strlen(exception_msg)),
147 "Got wrong message: %s", e.msg);
149 ("Got the expected exception when calling the exception raising RPC");
154 THROW0(unknown_error, 0, "Didn't got the remote exception!");
156 INFO0("Called the exception raising RPC");
157 exception_catching();
160 for (i = 0; i < 5; i++) {
162 INFO1("Call the exception raising RPC (i=%d)", i);
164 gras_msg_rpccall(toserver, 6000.0, "raise exception", NULL, NULL);
171 THROW0(unknown_error, 0, "Didn't got the remote exception!");
176 /* 9. Call a RPC which raises an exception (to test that exception propagation works) */
177 for (i = 0; i < 5; i++) {
178 INFO1("Call the exception raising RPC on the forwarder (i=%d)", i);
180 gras_msg_rpccall(toforwarder, 6000.0, "forward exception", NULL, NULL);
186 THROW0(unknown_error, 0, "Didn't got the remote exception!");
188 xbt_assert1(e.value == 42, "Got wrong value: %d (!=42)", e.value);
189 xbt_assert1(!strncmp(e.msg, exception_msg, strlen(exception_msg)),
190 "Got wrong message: %s", e.msg);
191 xbt_assert2(e.category == unknown_error,
192 "Got wrong category: %d (instead of %d)",
193 e.category, unknown_error);
195 ("Got the expected exception when calling the exception raising RPC");
197 exception_catching();
200 INFO2("Ask %s:%d to die", gras_socket_peer_name(toforwarder),
201 gras_socket_peer_port(toforwarder));
202 gras_msg_send(toforwarder, "kill", NULL);
203 INFO2("Ask %s:%d to die", gras_socket_peer_name(toserver),
204 gras_socket_peer_port(toserver));
205 gras_msg_send(toserver, "kill", NULL);
207 /* 11. Cleanup the place before leaving */
208 gras_socket_close(toserver);
209 gras_socket_close(toforwarder);
213 } /* end_of_client */
216 /* **********************************************************************
218 * **********************************************************************/
220 gras_socket_t server;
222 } s_forward_data_t, *forward_data_t;
224 static int forwarder_cb_kill(gras_msg_cb_ctx_t ctx, void *payload_data)
226 forward_data_t fdata;
227 gras_socket_t expeditor = gras_msg_cb_ctx_from(ctx);
228 INFO2("Asked to die by %s:%d", gras_socket_peer_name(expeditor),
229 gras_socket_peer_port(expeditor));
230 fdata = gras_userdata_get();
235 static int forwarder_cb_forward_ex(gras_msg_cb_ctx_t ctx, void *payload_data)
237 forward_data_t fdata = gras_userdata_get();
239 INFO0("Forward a request");
240 gras_msg_rpccall(fdata->server, 60, "raise exception", NULL, NULL);
244 int forwarder(int argc, char *argv[])
246 gras_socket_t mysock;
248 forward_data_t fdata;
250 gras_init(&argc, argv);
252 xbt_assert(argc == 4);
254 fdata = gras_userdata_new(s_forward_data_t);
256 port = atoi(argv[1]);
258 INFO1("Launch forwarder (port=%d)", port);
259 mysock = gras_socket_server(port);
261 gras_os_sleep(1); /* wait for the server to be ready */
262 fdata->server = gras_socket_client(argv[2], atoi(argv[3]));
265 gras_cb_register("forward exception", &forwarder_cb_forward_ex);
266 gras_cb_register("kill", &forwarder_cb_kill);
268 while (!fdata->done) {
269 gras_msg_handle(600.0);
272 gras_socket_close(mysock);
273 gras_socket_close(fdata->server);
280 /* **********************************************************************
282 * **********************************************************************/
284 gras_socket_t server;
286 } s_server_data_t, *server_data_t;
288 static int server_cb_kill(gras_msg_cb_ctx_t ctx, void *payload_data)
290 gras_socket_t expeditor = gras_msg_cb_ctx_from(ctx);
293 INFO2("Asked to die by %s:%d", gras_socket_peer_name(expeditor),
294 gras_socket_peer_port(expeditor));
296 sdata = gras_userdata_get();
301 static int server_cb_raise_ex(gras_msg_cb_ctx_t ctx, void *payload_data)
307 static int server_cb_ping(gras_msg_cb_ctx_t ctx, void *payload_data)
310 /* 1. Get the payload into the msg variable, and retrieve who called us */
311 int msg = *(int *) payload_data;
312 gras_socket_t expeditor = gras_msg_cb_ctx_from(ctx);
314 /* 2. Log which client connected */
315 INFO3("Got message PING(%d) from %s:%d",
317 gras_socket_peer_name(expeditor), gras_socket_peer_port(expeditor));
319 /* 4. Change the value of the msg variable */
322 /* 5. Return as result */
323 gras_msg_rpcreturn(6000, ctx, &msg);
324 INFO0("Answered with PONG(4321)");
326 /* 6. Cleanups, if any */
328 /* 7. Tell GRAS that we consummed this message */
330 } /* end_of_server_cb_ping */
333 int server(int argc, char *argv[])
335 gras_socket_t mysock;
340 /* 1. Init the GRAS infrastructure */
341 gras_init(&argc, argv);
343 /* 2. Get the port I should listen on from the command line, if specified */
345 port = atoi(argv[1]);
347 sdata = gras_userdata_new(s_server_data_t);
350 INFO1("Launch server (port=%d)", port);
352 /* 3. Create my master socket */
353 mysock = gras_socket_server(port);
355 /* 4. Register the known messages and register my callback */
357 gras_cb_register("plain ping", &server_cb_ping);
358 gras_cb_register("raise exception", &server_cb_raise_ex);
359 gras_cb_register("kill", &server_cb_kill);
361 INFO1("Listening on port %d", gras_socket_my_port(mysock));
363 /* 5. Wait for the ping incomming messages */
365 /** \bug if the server is gone before the forwarder tries to connect,
366 it dies awfully with the following message. The problem stands somewhere
367 at the interface between the gras_socket_t and the msg mess. There is thus
368 no way for me to dive into this before this interface is rewritten
369 ==15875== Invalid read of size 4
370 ==15875== at 0x408B805: find_port (transport_plugin_sg.c:68)
371 ==15875== by 0x408BD64: gras_trp_sg_socket_client (transport_plugin_sg.c:115)
372 ==15875== by 0x404A38B: gras_socket_client_ext (transport.c:255)
373 ==15875== by 0x404A605: gras_socket_client (transport.c:288)
374 ==15875== by 0x804B49D: forwarder (rpc.c:245)
375 ==15875== by 0x80491FB: launch_forwarder (_rpc_simulator.c:52)
376 ==15875== by 0x406780B: __context_wrapper (context.c:164)
377 ==15875== by 0x41A6CB3: pthread_start_thread (manager.c:310)
378 ==15875== by 0x42AA549: clone (clone.S:119)
379 ==15875== Address 0x433B49C is 44 bytes inside a block of size 48 free'd
380 ==15875== at 0x401CF46: free (vg_replace_malloc.c:235)
381 ==15875== by 0x408F1FA: gras_process_exit (sg_process.c:117)
382 ==15875== by 0x4049386: gras_exit (gras.c:64)
383 ==15875== by 0x804B936: server (rpc.c:345)
384 ==15875== by 0x80492B1: launch_server (_rpc_simulator.c:69)
385 ==15875== by 0x406780B: __context_wrapper (context.c:164)
386 ==15875== by 0x41A6CB3: pthread_start_thread (manager.c:310)
387 ==15875== by 0x42AA549: clone (clone.S:119)
389 while (!sdata->done) {
390 gras_msg_handle(600.0);
391 exception_catching();
394 /* 8. Free the allocated resources, and shut GRAS down */
396 gras_socket_close(mysock);
401 } /* end_of_server */