Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
28ae63b1eef4ae4c9a04e414d93ce9be34d6c32f
[simgrid.git] / examples / gras / rpc / rpc.c
1 /* $Id$ */
2
3 /* rpc - demo of the RPC features in GRAS                                   */
4
5 /* Copyright (c) 2006 Martin Quinson. All rights reserved.                  */
6
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. */
9
10 #include "gras.h"
11
12 XBT_LOG_NEW_DEFAULT_CATEGORY(Rpc,"Messages specific to this example");
13
14 /* register messages which may be sent (common to client and server) */
15 static void register_messages(void) {
16   gras_msgtype_declare_rpc("plain ping",
17                            gras_datadesc_by_name("int"),
18                            gras_datadesc_by_name("int"));
19
20   gras_msgtype_declare_rpc("raise exception", NULL, NULL);
21   gras_msgtype_declare_rpc("forward exception", NULL, NULL);
22 }
23
24 /* Function prototypes */
25 int server (int argc,char *argv[]);
26 int forwarder (int argc,char *argv[]);
27 int client (int argc,char *argv[]);
28
29 /* **********************************************************************
30  * Client code
31  * **********************************************************************/
32
33
34 int client(int argc,char *argv[]) {
35   xbt_ex_t e; 
36   gras_socket_t toserver=NULL; /* peer */
37   gras_socket_t toforwarder=NULL; /* peer */
38
39   
40
41   int ping, pong, i;
42   volatile int gotit=0;
43
44   const char *host = "127.0.0.1";
45         int   port = 4000;
46
47   /* 1. Init the GRAS's infrastructure */
48   gras_init(&argc, argv);
49    
50   /* 2. Get the server's address. The command line override defaults when specified */
51   if (argc == 5) {
52     host=argv[1];
53     port=atoi(argv[2]);
54   } 
55
56   INFO2("Launch client (server on %s:%d)",host,port);
57    
58   /* 3. Wait for the server startup */
59   gras_os_sleep(1);
60    
61   /* 4. Create a socket to speak to the server */
62   TRY {
63     toserver=gras_socket_client(host,port);
64     toforwarder=gras_socket_client(argv[3],atoi(argv[4]));
65   } CATCH(e) {
66     RETHROW0("Unable to connect to the server: %s");
67   }
68   INFO2("Connected to %s:%d.",host,port);    
69
70
71   /* 5. Register the messages. 
72         See, it doesn't have to be done completely at the beginning,
73         but only before use */
74   register_messages();
75
76   /* 6. Keep the user informed of what's going on */
77   INFO2("Connected to server which is on %s:%d ", 
78         gras_socket_peer_name(toserver),gras_socket_peer_port(toserver));
79
80   /* 7. Prepare and send the ping message to the server */
81   ping = 1234;
82   TRY {
83     gras_msg_rpccall(toserver, 6000.0,
84                      gras_msgtype_by_name("plain ping"), &ping, &pong);
85   } CATCH(e) {
86     gras_socket_close(toserver);
87     RETHROW0("Failed to execute a PING rpc on the server: %s");
88   }
89
90   /* 8. Keep the user informed of what's going on, again */
91   INFO4("The answer to PING(%d) on %s:%d is PONG(%d)  ", 
92         ping, 
93         gras_socket_peer_name(toserver),gras_socket_peer_port(toserver),
94         pong);
95
96   /* 9. Call a RPC which raises an exception (to test that exception propagation works) */
97   INFO0("Call the exception raising RPC");
98   TRY {
99     gras_msg_rpccall(toserver, 6000.0,
100                      gras_msgtype_by_name("raise exception"), NULL, NULL);
101   } CATCH(e) {
102     gotit = 1;
103   }
104   if (!gotit) {
105     THROW0(unknown_error,0,"Didn't got the remote exception!");
106   }
107   xbt_assert2(e.category == unknown_error, "Got wrong category: %d (instead of %d)", 
108               e.category,unknown_error);
109   xbt_assert1(e.value == 42, "Got wrong value: %d (!=42)", e.value);
110   xbt_assert1(!strcmp(e.msg,"Some error we will catch on client side"), 
111               "Got wrong message: %s", e.msg);;
112   INFO0("Got the expected exception when calling the exception raising RPC");
113   xbt_ex_free(e);
114
115   /* doxygen_ignore */
116   for (i=0; i<5; i++) {
117         
118      INFO1("Call the exception raising RPC (i=%d)",i);
119      TRY {
120         gras_msg_rpccall(toserver, 6000.0,
121                          gras_msgtype_by_name("raise exception"), NULL, NULL);
122      } CATCH(e) {
123         gotit = 1;
124         xbt_ex_free(e);
125      }
126      if (!gotit) {
127         THROW0(unknown_error,0,"Didn't got the remote exception!");
128      }
129   }
130   /* doxygen_resume */
131   
132   /* 9. Call a RPC which raises an exception (to test that exception propagation works) */
133   for (i=0;i<2;i++) {
134     INFO1("Call the exception raising RPC on the forwarder (i=%d)",i);
135     TRY {
136       gras_msg_rpccall(toforwarder, 6000.0,
137                        gras_msgtype_by_name("forward exception"), NULL, NULL);
138     } CATCH(e) {
139       gotit = 1;
140     }
141     if (!gotit) {
142       THROW0(unknown_error,0,"Didn't got the remote exception!");
143     }
144     xbt_assert1(e.category == unknown_error, "Got wrong category: %d", e.category);
145     xbt_assert1(e.value == 42, "Got wrong value: %d (!=42)", e.value);
146     xbt_assert1(!strcmp(e.msg,"Some error we will catch on client side"), 
147                 "Got wrong message: %s", e.msg);;
148     INFO0("Got the expected exception when calling the exception raising RPC");
149     xbt_ex_free(e);
150   }
151
152   /* 11. Cleanup the place before leaving */
153   gras_socket_close(toserver);
154   gras_exit();
155   INFO0("Done.");
156   return 0;
157 } /* end_of_client */
158
159
160 /* **********************************************************************
161  * Forwarder code
162  * **********************************************************************/
163 typedef struct {
164   gras_socket_t server;
165 } s_forward_data_t, *forward_data_t;
166
167 static int server_cb_forward_ex(gras_msg_cb_ctx_t ctx,
168                               void             *payload_data) {
169   forward_data_t fdata=gras_userdata_get();
170
171   gras_msg_rpccall(fdata->server, 60, gras_msgtype_by_name("raise exception"),NULL,NULL);
172   return 1;
173 }
174
175 int forwarder (int argc,char *argv[]) {
176   gras_socket_t mysock;
177   int port;
178   forward_data_t fdata;
179
180   gras_init(&argc,argv);
181
182   xbt_assert(argc == 4);
183
184   fdata=gras_userdata_new(s_forward_data_t);
185   port=atoi(argv[1]);
186
187   INFO1("Launch forwarder (port=%d)", port);
188   mysock = gras_socket_server(port);
189
190   gras_os_sleep(0.1); /* wait for the server to be ready */
191   fdata->server=gras_socket_client(argv[2],atoi(argv[3]));
192
193   register_messages();
194   gras_cb_register(gras_msgtype_by_name("forward exception"),&server_cb_forward_ex);
195
196   gras_msg_handle(600.0); /* deal with the first forwarded request */
197   gras_msg_handle(600.0); /* deal with the second forwarded request */
198   gras_socket_close(mysock);
199   gras_socket_close(fdata->server);
200   free(fdata);
201   gras_exit();
202   INFO0("Done.");
203   return 0;
204 }
205
206 /* **********************************************************************
207  * Server code
208  * **********************************************************************/
209
210 static int server_cb_raise_ex(gras_msg_cb_ctx_t ctx,
211                                 void             *payload_data) {
212   THROW0(unknown_error,42,"Some error we will catch on client side");
213 }
214
215 static int server_cb_ping(gras_msg_cb_ctx_t ctx,
216                           void             *payload_data) {
217                              
218   /* 1. Get the payload into the msg variable, and retrieve who called us */
219   int msg=*(int*)payload_data;
220   gras_socket_t expeditor = gras_msg_cb_ctx_from(ctx);
221    
222   /* 2. Log which client connected */
223   INFO3("Got message PING(%d) from %s:%d ", 
224         msg, 
225         gras_socket_peer_name(expeditor), gras_socket_peer_port(expeditor));
226   
227   /* 4. Change the value of the msg variable */
228   msg = 4321;
229
230   /* 5. Return as result */
231   gras_msg_rpcreturn(6000,ctx,&msg);
232   INFO0("Answered with PONG(4321)");
233      
234   /* 6. Cleanups, if any */
235
236   /* 7. Tell GRAS that we consummed this message */
237   return 1;
238 } /* end_of_server_cb_ping */
239
240
241 int server (int argc,char *argv[]) {
242   gras_socket_t mysock;
243
244   int port = 4000;
245   int i;
246   
247   /* 1. Init the GRAS infrastructure */
248   gras_init(&argc,argv);
249    
250   /* 2. Get the port I should listen on from the command line, if specified */
251   if (argc == 2) 
252     port=atoi(argv[1]);
253
254   INFO1("Launch server (port=%d)", port);
255
256   /* 3. Create my master socket */
257   mysock = gras_socket_server(port);
258
259   /* 4. Register the known messages and register my callback */
260   register_messages();
261   gras_cb_register(gras_msgtype_by_name("plain ping"),&server_cb_ping);
262   gras_cb_register(gras_msgtype_by_name("raise exception"),&server_cb_raise_ex);
263
264   INFO1("Listening on port %d ", gras_socket_my_port(mysock));
265
266   /* 5. Wait for the ping incomming messages */
267   gras_msg_handle(600.0);
268   /* 6. Wait for the exception raiser incomming messages */
269   gras_msg_handle(600.0);
270   /* doxygen_ignore */
271   for (i=0; i<5; i++)
272      gras_msg_handle(600.0);
273   /* doxygen_resume */
274
275   /* 7. Wait for the exception forwarder incomming messages (twice, to see if it triggers bugs) */
276   gras_msg_handle(600.0); 
277   gras_msg_handle(600.0); 
278    
279   /* 8. Free the allocated resources, and shut GRAS down */
280   gras_socket_close(mysock);
281   gras_exit();
282    
283   INFO0("Done.");
284   return 0;
285 } /* end_of_server */
286