Logo AND Algorithmique Numérique Distribuée

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