Logo AND Algorithmique Numérique Distribuée

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