Logo AND Algorithmique Numérique Distribuée

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