Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
f6014ee4132a6ad760d27b26afb15e2e142a11ae
[simgrid.git] / src / gras / Transport / transport.c
1 /* $Id$ */
2
3 /* transport - low level communication                                      */
4
5 /* Authors: Martin Quinson                                                  */
6 /* Copyright (C) 2004 Martin Quinson.                                       */
7
8 /* This program is free software; you can redistribute it and/or modify it
9    under the terms of the license (GNU LGPL) which comes with this package. */
10
11 #include "gras/Transport/transport_private.h"
12
13 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(transport,gras,"Conveying bytes over the network");
14
15 static gras_dict_t  *_gras_trp_plugins;     /* All registered plugins */
16 static void gras_trp_plugin_free(void *p); /* free one of the plugins */
17
18 static void gras_trp_socket_free(void *s); /* free one socket */
19
20 static void
21 gras_trp_plugin_new(const char *name, gras_trp_setup_t setup) {
22   gras_error_t errcode;
23
24   gras_trp_plugin_t *plug = gras_new0(gras_trp_plugin_t, 1);
25   
26   DEBUG1("Create plugin %s",name);
27
28   plug->name=gras_strdup(name);
29
30   errcode = setup(plug);
31   switch (errcode) {
32   case mismatch_error:
33     /* SG plugin return mismatch when in RL mode (and vice versa) */
34     gras_free(plug->name);
35     gras_free(plug);
36     break;
37
38   case no_error:
39     gras_dict_set(_gras_trp_plugins,
40                   name, plug, gras_trp_plugin_free);
41     break;
42
43   default:
44     DIE_IMPOSSIBLE;
45   }
46
47 }
48
49 void
50 gras_trp_init(void){
51   
52   /* make room for all plugins */
53   gras_dict_new(&_gras_trp_plugins);
54
55   /* Add them */
56   gras_trp_plugin_new("tcp", gras_trp_tcp_setup);
57   gras_trp_plugin_new("file",gras_trp_file_setup);
58   gras_trp_plugin_new("sg",gras_trp_sg_setup);
59
60   /* buf is composed, so it must come after the others */
61   gras_trp_plugin_new("buf", gras_trp_buf_setup);
62
63 }
64
65 void
66 gras_trp_exit(void){
67   gras_dict_free(&_gras_trp_plugins);
68 }
69
70
71 void gras_trp_plugin_free(void *p) {
72   gras_trp_plugin_t *plug = p;
73
74   if (plug) {
75     if (plug->exit) {
76       plug->exit(plug);
77     } else if (plug->data) {
78       DEBUG1("Plugin %s lacks exit(). Free data anyway.",plug->name);
79       gras_free(plug->data);
80     }
81
82     gras_free(plug->name);
83     gras_free(plug);
84   }
85 }
86
87
88 /**
89  * gras_trp_socket_new:
90  *
91  * Malloc a new socket, and initialize it with defaults
92  */
93 void gras_trp_socket_new(int incoming,
94                          gras_socket_t **dst) {
95
96   gras_socket_t *sock=gras_new(gras_socket_t,1);
97
98   DEBUG1("Create a new socket (%p)", (void*)sock);
99
100   sock->plugin = NULL;
101   sock->sd     = -1;
102   sock->data   = NULL;
103
104   sock->incoming  = incoming ? 1:0;
105   sock->outgoing  = incoming ? 0:1;
106   sock->accepting = incoming ? 1:0;
107
108   sock->port      = -1;
109   sock->peer_port = -1;
110   sock->peer_name = NULL;
111   sock->raw = 0;
112
113   *dst = sock;
114
115   gras_dynar_push(gras_socketset_get(),dst);
116 }
117
118
119 /**
120  * gras_socket_server_ext:
121  *
122  * Opens a server socket and make it ready to be listened to.
123  * In real life, you'll get a TCP socket.
124  */
125 gras_error_t
126 gras_socket_server_ext(unsigned short port,
127                        
128                        unsigned long int bufSize,
129                        int raw,
130                        
131                        /* OUT */ gras_socket_t **dst) {
132  
133   gras_error_t errcode;
134   gras_trp_plugin_t *trp;
135   gras_socket_t *sock;
136
137   *dst = NULL;
138
139   DEBUG1("Create a server socket from plugin %s",gras_if_RL() ? "tcp" : "sg");
140   TRY(gras_trp_plugin_get_by_name("buf",&trp));
141
142   /* defaults settings */
143   gras_trp_socket_new(1,&sock);
144   sock->plugin= trp;
145   sock->port=port;
146   sock->bufSize = bufSize;
147   sock->raw = raw;
148
149   /* Call plugin socket creation function */
150   errcode = trp->socket_server(trp, sock);
151   DEBUG3("in=%c out=%c accept=%c",
152          sock->incoming?'y':'n', 
153          sock->outgoing?'y':'n',
154          sock->accepting?'y':'n');
155
156   if (errcode != no_error) {
157     gras_free(sock);
158     return errcode;
159   }
160
161   *dst = sock;
162
163   return no_error;
164 }
165    
166 /**
167  * gras_socket_client_ext:
168  *
169  * Opens a client socket to a remote host.
170  * In real life, you'll get a TCP socket.
171  */
172 gras_error_t
173 gras_socket_client_ext(const char *host,
174                        unsigned short port,
175                        
176                        unsigned long int bufSize,
177                        int raw,
178                        
179                        /* OUT */ gras_socket_t **dst) {
180  
181   gras_error_t errcode;
182   gras_trp_plugin_t *trp;
183   gras_socket_t *sock;
184
185   *dst = NULL;
186
187   TRY(gras_trp_plugin_get_by_name("buf",&trp));
188
189   DEBUG1("Create a client socket from plugin %s",gras_if_RL() ? "tcp" : "sg");
190   /* defaults settings */
191   gras_trp_socket_new(0,&sock);
192   sock->plugin= trp;
193   sock->peer_port = port;
194   sock->peer_name = (char*)strdup(host?host:"localhost");
195   sock->bufSize = bufSize;
196   sock->raw = raw;
197
198   /* plugin-specific */
199   errcode= (*trp->socket_client)(trp, sock);
200   DEBUG3("in=%c out=%c accept=%c",
201          sock->incoming?'y':'n', 
202          sock->outgoing?'y':'n',
203          sock->accepting?'y':'n');
204
205   if (errcode != no_error) {
206     gras_free(sock);
207     return errcode;
208   }
209
210   *dst = sock;
211
212   return no_error;
213 }
214
215 /**
216  * gras_socket_server:
217  *
218  * Opens a server socket and make it ready to be listened to.
219  * In real life, you'll get a TCP socket.
220  */
221 gras_error_t
222 gras_socket_server(unsigned short port,
223                    /* OUT */ gras_socket_t **dst) {
224    return gras_socket_server_ext(port,32,0,dst);
225 }
226
227 /**
228  * gras_socket_client:
229  *
230  * Opens a client socket to a remote host.
231  * In real life, you'll get a TCP socket.
232  */
233 gras_error_t
234 gras_socket_client(const char *host,
235                    unsigned short port,
236                    /* OUT */ gras_socket_t **dst) {
237    return gras_socket_client_ext(host,port,32,0,dst);
238 }
239
240
241 void gras_socket_close(gras_socket_t *sock) {
242   gras_dynar_t *sockets = gras_socketset_get();
243   gras_socket_t *sock_iter;
244   int cursor;
245
246   /* FIXME: Issue an event when the socket is closed */
247   if (sock) {
248     gras_dynar_foreach(sockets,cursor,sock_iter) {
249       if (sock == sock_iter) {
250         gras_dynar_cursor_rm(sockets,&cursor);
251         if ( sock->plugin->socket_close) 
252           (* sock->plugin->socket_close)(sock);
253
254         /* free the memory */
255         if (sock->peer_name)
256           gras_free(sock->peer_name);
257         gras_free(sock);
258         return;
259       }
260     }
261     WARN0("Ignoring request to free an unknown socket");
262   }
263 }
264
265 /**
266  * gras_trp_chunk_send:
267  *
268  * Send a bunch of bytes from on socket
269  */
270 gras_error_t
271 gras_trp_chunk_send(gras_socket_t *sd,
272                     char *data,
273                     long int size) {
274   gras_assert1(sd->outgoing,
275                "Socket not suited for data send (outgoing=%c)",
276                sd->outgoing?'y':'n');
277   gras_assert1(sd->plugin->chunk_send,
278                "No function chunk_send on transport plugin %s",
279                sd->plugin->name);
280   return (*sd->plugin->chunk_send)(sd,data,size);
281 }
282 /**
283  * gras_trp_chunk_recv:
284  *
285  * Receive a bunch of bytes from a socket
286  */
287 gras_error_t 
288 gras_trp_chunk_recv(gras_socket_t *sd,
289                     char *data,
290                     long int size) {
291   gras_assert0(sd->incoming,
292                "Socket not suited for data receive");
293   gras_assert1(sd->plugin->chunk_recv,
294                "No function chunk_recv on transport plugin %s",
295                sd->plugin->name);
296   return (sd->plugin->chunk_recv)(sd,data,size);
297 }
298
299 /**
300  * gras_trp_flush:
301  *
302  * Make sure all pending communications are done
303  */
304 gras_error_t 
305 gras_trp_flush(gras_socket_t *sd) {
306   return (sd->plugin->flush)(sd);
307 }
308
309 gras_error_t
310 gras_trp_plugin_get_by_name(const char *name,
311                             gras_trp_plugin_t **dst){
312
313   return gras_dict_get(_gras_trp_plugins,name,(void**)dst);
314 }
315
316 int   gras_socket_my_port  (gras_socket_t *sock) {
317   return sock->port;
318 }
319 int   gras_socket_peer_port(gras_socket_t *sock) {
320   return sock->peer_port;
321 }
322 char *gras_socket_peer_name(gras_socket_t *sock) {
323   return sock->peer_name;
324 }
325
326 gras_error_t gras_socket_raw_send(gras_socket_t *peer, 
327                                   unsigned int timeout,
328                                   unsigned long int expSize, 
329                                   unsigned long int msgSize) {
330   
331   gras_assert0(peer->raw,"Asked to send raw data on a regular socket\n");
332   return gras_socket_raw_exchange(peer,1,timeout,expSize,msgSize);   
333 }
334
335 gras_error_t gras_socket_raw_recv(gras_socket_t *peer, 
336                                   unsigned int timeout,
337                                   unsigned long int expSize, 
338                                   unsigned long int msgSize){
339   
340   gras_assert0(peer->raw,"Asked to recveive raw data on a regular socket\n");
341   return gras_socket_raw_exchange(peer,0,timeout,expSize,msgSize);   
342 }