Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Create a new log channel tbx containing dict, set, log, dynar, config (to shut
[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);
51     break;
52
53   case no_error:
54     TRY(gras_dict_set(_gras_trp_plugins, 
55                       name, plug, gras_trp_plugin_free));
56     break;
57
58   default:
59     free(plug);
60     return errcode;
61   }
62   return no_error;
63 }
64
65 gras_error_t 
66 gras_trp_init(void){
67   gras_error_t errcode;
68   
69   /* make room for all socket ownership descriptions */
70   TRY(gras_dynar_new(&_gras_trp_sockets, sizeof(gras_socket_t*), NULL));
71
72   /* We do not ear for any socket for now */
73   FD_ZERO(&FDread);
74   
75   /* make room for all plugins */
76   TRY(gras_dict_new(&_gras_trp_plugins));
77
78   /* Add them */
79   TRY(gras_trp_plugin_new("tcp", gras_trp_tcp_setup));
80   TRY(gras_trp_plugin_new("file",gras_trp_file_setup));
81   TRY(gras_trp_plugin_new("sg",gras_trp_sg_setup));
82
83   return no_error;
84 }
85
86 void
87 gras_trp_exit(void){
88   gras_dict_free(&_gras_trp_plugins);
89   gras_dynar_free(_gras_trp_sockets);
90 }
91
92
93 void gras_trp_plugin_free(void *p) {
94   gras_trp_plugin_t *plug = p;
95
96   if (plug) {
97     if (plug->exit) {
98       plug->exit(plug);
99     } else if (plug->data) {
100       DEBUG1("Plugin %s lacks exit(). Free data anyway.",plug->name);
101       free(plug->data);
102     }
103
104     free(plug->name);
105     free(plug);
106   }
107 }
108
109
110 /**
111  * gras_trp_socket_new:
112  *
113  * Malloc a new socket, and initialize it with defaults
114  */
115 gras_error_t gras_trp_socket_new(int incoming,
116                                  gras_socket_t **dst) {
117
118   gras_socket_t *sock;
119
120   if (! (sock=malloc(sizeof(gras_socket_t))) )
121     RAISE_MALLOC;
122
123   sock->plugin = NULL;
124   sock->sd     = -1;
125
126   sock->incoming  = incoming ? 1:0;
127   sock->outgoing  = incoming ? 0:1;
128   sock->accepting = incoming ? 1:0;
129
130   sock->port      = -1;
131   sock->peer_port = -1;
132   sock->peer_name = NULL;
133   sock->raw = 0;
134
135   *dst = sock;
136   return no_error;
137 }
138
139
140 /**
141  * gras_socket_server:
142  *
143  * Opens a server socket and make it ready to be listened to.
144  * In real life, you'll get a TCP socket.
145  */
146 gras_error_t
147 gras_socket_server(unsigned short port,
148                    /* OUT */ gras_socket_t **dst) {
149  
150   gras_error_t errcode;
151   gras_trp_plugin_t *trp;
152   gras_socket_t *sock;
153
154   *dst = NULL;
155
156   DEBUG1("Create a server socket from plugin %s",gras_if_RL() ? "tcp" : "sg");
157   TRY(gras_trp_plugin_get_by_name(gras_if_RL() ? "tcp" : "sg",
158                                   &trp));
159
160   /* defaults settings */
161   TRY(gras_trp_socket_new(1,&sock));
162   sock->plugin= trp;
163   sock->port=port;
164
165   /* Call plugin socket creation function */
166   errcode = trp->socket_server(trp, port, sock);
167   DEBUG3("in=%c out=%c accept=%c",
168          sock->incoming?'y':'n', 
169          sock->outgoing?'y':'n',
170          sock->accepting?'y':'n');
171
172   if (errcode != no_error) {
173     free(sock);
174     return errcode;
175   }
176
177   *dst = sock;
178   /* Register this socket */
179   errcode = gras_dynar_push(_gras_trp_sockets,dst);
180   if (errcode != no_error) {
181     free(sock);
182     *dst = NULL;
183     return errcode;
184   }
185
186   return no_error;
187 }
188
189 /**
190  * gras_socket_client:
191  *
192  * Opens a client socket to a remote host.
193  * In real life, you'll get a TCP socket.
194  */
195 gras_error_t
196 gras_socket_client(const char *host,
197                    unsigned short port,
198                    /* OUT */ gras_socket_t **dst) {
199  
200   gras_error_t errcode;
201   gras_trp_plugin_t *trp;
202   gras_socket_t *sock;
203
204   *dst = NULL;
205
206   TRY(gras_trp_plugin_get_by_name(gras_if_RL() ? "tcp" : "sg",
207                                   &trp));
208
209   /* defaults settings */
210   TRY(gras_trp_socket_new(0,&sock));
211   sock->plugin= trp;
212   sock->peer_port = port;
213   sock->peer_name = strdup(host?host:"localhost");
214
215   /* plugin-specific */
216   errcode= (* trp->socket_client)(trp, 
217                                   host ? host : "localhost", port,
218                                   sock);
219   DEBUG3("in=%c out=%c accept=%c",
220          sock->incoming?'y':'n', 
221          sock->outgoing?'y':'n',
222          sock->accepting?'y':'n');
223
224   if (errcode != no_error) {
225     free(sock);
226     return errcode;
227   }
228
229   /* register socket */
230   *dst = sock;
231   errcode = gras_dynar_push(_gras_trp_sockets,dst);
232   if (errcode != no_error) {
233     free(sock);
234     *dst = NULL;
235     return errcode;
236   }
237
238   return no_error;
239 }
240
241 void gras_socket_close(gras_socket_t **sock) {
242   gras_socket_t *sock_iter;
243   int cursor;
244
245   /* FIXME: Issue an event when the socket is closed */
246   if (sock && *sock) {
247     gras_dynar_foreach(_gras_trp_sockets,cursor,sock_iter) {
248       if (*sock == sock_iter) {
249         gras_dynar_cursor_rm(_gras_trp_sockets,&cursor);
250         if ( (*sock)->plugin->socket_close) 
251           (* (*sock)->plugin->socket_close)(*sock);
252
253         /* free the memory */
254         free(*sock);
255         *sock=NULL;
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 }