Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Make sure that examples/ping/test_rl and examples/ping/test_sg are executable
[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 <time.h>       /* time() */
12
13 #include "Transport/transport_private.h"
14
15 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(transport,GRAS);
16
17 static gras_dict_t  *_gras_trp_plugins;     /* All registered plugins */
18 static void gras_trp_plugin_free(void *p); /* free one of the plugins */
19
20
21 gras_dynar_t *_gras_trp_sockets; /* all existing sockets */
22 static void gras_trp_socket_free(void *s); /* free one socket */
23
24 static fd_set FDread;
25
26 gras_error_t
27 gras_trp_plugin_new(const char *name, gras_trp_setup_t setup);
28
29 gras_error_t
30 gras_trp_plugin_new(const char *name, gras_trp_setup_t setup) {
31   gras_error_t errcode;
32
33   gras_trp_plugin_t *plug = malloc(sizeof(gras_trp_plugin_t));
34   
35   DEBUG1("Create plugin %s",name);
36
37   if (!plug) 
38     RAISE_MALLOC;
39
40   memset(plug,0,sizeof(gras_trp_plugin_t));
41
42   plug->name=strdup(name);
43   if (!plug->name)
44     RAISE_MALLOC;
45
46   errcode = setup(plug);
47   switch (errcode) {
48   case mismatch_error:
49     /* SG plugin return mismatch when in RL mode (and vice versa) */
50     free(plug->name);
51     free(plug);
52     break;
53
54   case no_error:
55     TRY(gras_dict_set(_gras_trp_plugins, 
56                       name, plug, gras_trp_plugin_free));
57     break;
58
59   default:
60     free(plug);
61     return errcode;
62   }
63   return no_error;
64 }
65
66 gras_error_t 
67 gras_trp_init(void){
68   gras_error_t errcode;
69   
70   /* make room for all socket ownership descriptions */
71   TRY(gras_dynar_new(&_gras_trp_sockets, sizeof(gras_socket_t*), NULL));
72
73   /* We do not ear for any socket for now */
74   FD_ZERO(&FDread);
75   
76   /* make room for all plugins */
77   TRY(gras_dict_new(&_gras_trp_plugins));
78
79   /* Add them */
80   TRY(gras_trp_plugin_new("tcp", gras_trp_tcp_setup));
81   TRY(gras_trp_plugin_new("file",gras_trp_file_setup));
82   TRY(gras_trp_plugin_new("sg",gras_trp_sg_setup));
83
84   return no_error;
85 }
86
87 void
88 gras_trp_exit(void){
89   gras_dict_free(&_gras_trp_plugins);
90   gras_dynar_free(_gras_trp_sockets);
91 }
92
93
94 void gras_trp_plugin_free(void *p) {
95   gras_trp_plugin_t *plug = p;
96
97   if (plug) {
98     if (plug->exit) {
99       plug->exit(plug);
100     } else if (plug->data) {
101       DEBUG1("Plugin %s lacks exit(). Free data anyway.",plug->name);
102       free(plug->data);
103     }
104
105     free(plug->name);
106     free(plug);
107   }
108 }
109
110
111 /**
112  * gras_trp_socket_new:
113  *
114  * Malloc a new socket, and initialize it with defaults
115  */
116 gras_error_t gras_trp_socket_new(int incoming,
117                                  gras_socket_t **dst) {
118
119   gras_socket_t *sock;
120
121   if (! (sock=malloc(sizeof(gras_socket_t))) )
122     RAISE_MALLOC;
123
124   sock->plugin = NULL;
125   sock->sd     = -1;
126
127   sock->incoming  = incoming ? 1:0;
128   sock->outgoing  = incoming ? 0:1;
129   sock->accepting = incoming ? 1:0;
130
131   sock->port      = -1;
132   sock->peer_port = -1;
133   sock->peer_name = NULL;
134   sock->raw = 0;
135
136   *dst = sock;
137   return no_error;
138 }
139
140
141 /**
142  * gras_socket_server:
143  *
144  * Opens a server socket and make it ready to be listened to.
145  * In real life, you'll get a TCP socket.
146  */
147 gras_error_t
148 gras_socket_server(unsigned short port,
149                    /* OUT */ gras_socket_t **dst) {
150  
151   gras_error_t errcode;
152   gras_trp_plugin_t *trp;
153   gras_socket_t *sock;
154
155   *dst = NULL;
156
157   DEBUG1("Create a server socket from plugin %s",gras_if_RL() ? "tcp" : "sg");
158   TRY(gras_trp_plugin_get_by_name(gras_if_RL() ? "tcp" : "sg",
159                                   &trp));
160
161   /* defaults settings */
162   TRY(gras_trp_socket_new(1,&sock));
163   sock->plugin= trp;
164   sock->port=port;
165
166   /* Call plugin socket creation function */
167   errcode = trp->socket_server(trp, port, sock);
168   DEBUG3("in=%c out=%c accept=%c",
169          sock->incoming?'y':'n', 
170          sock->outgoing?'y':'n',
171          sock->accepting?'y':'n');
172
173   if (errcode != no_error) {
174     free(sock);
175     return errcode;
176   }
177
178   *dst = sock;
179   /* Register this socket */
180   errcode = gras_dynar_push(_gras_trp_sockets,dst);
181   if (errcode != no_error) {
182     free(sock);
183     *dst = NULL;
184     return errcode;
185   }
186
187   return no_error;
188 }
189
190 /**
191  * gras_socket_client:
192  *
193  * Opens a client socket to a remote host.
194  * In real life, you'll get a TCP socket.
195  */
196 gras_error_t
197 gras_socket_client(const char *host,
198                    unsigned short port,
199                    /* OUT */ gras_socket_t **dst) {
200  
201   gras_error_t errcode;
202   gras_trp_plugin_t *trp;
203   gras_socket_t *sock;
204
205   *dst = NULL;
206
207   TRY(gras_trp_plugin_get_by_name(gras_if_RL() ? "tcp" : "sg",
208                                   &trp));
209
210   /* defaults settings */
211   TRY(gras_trp_socket_new(0,&sock));
212   sock->plugin= trp;
213   sock->peer_port = port;
214   sock->peer_name = strdup(host?host:"localhost");
215
216   /* plugin-specific */
217   errcode= (* trp->socket_client)(trp, 
218                                   host ? host : "localhost", port,
219                                   sock);
220   DEBUG3("in=%c out=%c accept=%c",
221          sock->incoming?'y':'n', 
222          sock->outgoing?'y':'n',
223          sock->accepting?'y':'n');
224
225   if (errcode != no_error) {
226     free(sock);
227     return errcode;
228   }
229
230   /* register socket */
231   *dst = sock;
232   errcode = gras_dynar_push(_gras_trp_sockets,dst);
233   if (errcode != no_error) {
234     free(sock);
235     *dst = NULL;
236     return errcode;
237   }
238
239   return no_error;
240 }
241
242 void gras_socket_close(gras_socket_t *sock) {
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(_gras_trp_sockets,cursor,sock_iter) {
249       if (sock == sock_iter) {
250         gras_dynar_cursor_rm(_gras_trp_sockets,&cursor);
251         if ( sock->plugin->socket_close) 
252           (* sock->plugin->socket_close)(sock);
253
254         /* free the memory */
255         free(sock);
256         return;
257       }
258     }
259     WARN0("Ignoring request to free an unknown socket");
260   }
261 }
262
263 /**
264  * gras_trp_chunk_send:
265  *
266  * Send a bunch of bytes from on socket
267  */
268 gras_error_t
269 gras_trp_chunk_send(gras_socket_t *sd,
270                     char *data,
271                     size_t size) {
272   gras_assert1(sd->outgoing,
273                "Socket not suited for data send (outgoing=%c)",
274                sd->outgoing?'y':'n');
275   gras_assert1(sd->plugin->chunk_send,
276                "No function chunk_send on transport plugin %s",
277                sd->plugin->name);
278   return (*sd->plugin->chunk_send)(sd,data,size);
279 }
280 /**
281  * gras_trp_chunk_recv:
282  *
283  * Receive a bunch of bytes from a socket
284  */
285 gras_error_t 
286 gras_trp_chunk_recv(gras_socket_t *sd,
287                     char *data,
288                     size_t size) {
289   gras_assert0(sd->incoming,
290                "Socket not suited for data receive");
291   gras_assert1(sd->plugin->chunk_recv,
292                "No function chunk_recv on transport plugin %s",
293                sd->plugin->name);
294   return (sd->plugin->chunk_recv)(sd,data,size);
295 }
296
297
298 gras_error_t
299 gras_trp_plugin_get_by_name(const char *name,
300                             gras_trp_plugin_t **dst){
301
302   return gras_dict_get(_gras_trp_plugins,name,(void**)dst);
303 }
304
305 int   gras_socket_my_port  (gras_socket_t *sock) {
306   return sock->port;
307 }
308 int   gras_socket_peer_port(gras_socket_t *sock) {
309   return sock->peer_port;
310 }
311 char *gras_socket_peer_name(gras_socket_t *sock) {
312   return sock->peer_name;
313 }