Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Exchange master socket port number on client socket creation: gras_socket_peer_port...
[simgrid.git] / src / gras / Transport / transport_plugin_tcp.c
1 /* $Id$ */
2
3 /* buf trp (transport) - buffered transport using the TCP one               */
4
5 /* Copyright (c) 2004 Martin Quinson. All rights reserved.                  */
6
7 /* This program is free software; you can redistribute it and/or modify it
8  * under the terms of the license (GNU LGPL) which comes with this package. */
9
10 #include <stdlib.h>
11 #include <string.h>       /* memset */
12
13 #include "portable.h"
14 #include "xbt/misc.h"
15 #include "xbt/sysdep.h"
16 #include "xbt/ex.h"
17 #include "transport_private.h"
18
19 /* FIXME maybe READV is sometime a good thing? */
20 #undef HAVE_READV
21
22 #ifdef HAVE_READV
23 #include <sys/uio.h>
24 #endif       
25
26 #ifndef MIN
27 #define MIN(a,b) ((a)<(b)?(a):(b))
28 #endif
29
30 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(gras_trp_tcp,gras_trp,
31       "TCP buffered transport");
32
33 int _gras_master_socket_port = -1;
34 /***
35  *** Specific socket part
36  ***/
37
38 typedef enum { buffering_buf, buffering_iov } buffering_kind;
39
40 typedef struct {
41   int size;
42   char *data;
43   int pos; /* for receive; not exchanged over the net */
44 } gras_trp_buf_t;
45
46
47 struct gras_trp_bufdata_{
48   int buffsize;
49   gras_trp_buf_t in_buf;
50   gras_trp_buf_t out_buf;
51
52 #ifdef HAVE_READV
53   xbt_dynar_t in_buf_v;
54   xbt_dynar_t out_buf_v;
55 #endif
56
57   buffering_kind in;
58   buffering_kind out;
59 };
60
61
62 /*****************************/
63 /****[ SOCKET MANAGEMENT ]****/
64 /*****************************/
65 /* we exchange port number on client side on socket creation,
66    so we need to be able to talk right now. */
67 static inline void gras_trp_tcp_send(gras_socket_t sock, const char *data,
68                                      unsigned long int size);
69 static int gras_trp_tcp_recv(gras_socket_t sock, char *data,
70                              unsigned long int size);
71
72
73 static int _gras_tcp_proto_number(void);
74
75 static inline void gras_trp_sock_socket_client(gras_trp_plugin_t ignored,
76                                                gras_socket_t sock){
77   
78   struct sockaddr_in addr;
79   struct hostent *he;
80   struct in_addr *haddr;
81   int size = sock->buf_size; 
82   uint32_t myport = htonl(_gras_master_socket_port);
83
84   sock->incoming = 1; /* TCP sockets are duplex'ed */
85
86   sock->sd = socket (AF_INET, SOCK_STREAM, 0);
87   
88   if (sock->sd < 0) {
89     THROW1(system_error,0, "Failed to create socket: %s", sock_errstr);
90   }
91
92   if (setsockopt(sock->sd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)) ||
93       setsockopt(sock->sd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size))) {
94      WARN1("setsockopt failed, cannot set buffer size: %s",sock_errstr);
95   }
96   
97   he = gethostbyname (sock->peer_name);
98   if (he == NULL) {
99     THROW2(system_error,0, "Failed to lookup hostname %s: %s",
100            sock->peer_name, sock_errstr);
101   }
102   
103   haddr = ((struct in_addr *) (he->h_addr_list)[0]);
104   
105   memset(&addr, 0, sizeof(struct sockaddr_in));
106   memcpy (&addr.sin_addr, haddr, sizeof(struct in_addr));
107   addr.sin_family = AF_INET;
108   addr.sin_port = htons (sock->peer_port);
109
110   if (connect (sock->sd, (struct sockaddr*) &addr, sizeof (addr)) < 0) {
111     tcp_close(sock->sd);
112     THROW3(system_error,0,
113            "Failed to connect socket to %s:%d (%s)",
114            sock->peer_name, sock->peer_port, sock_errstr);
115   }
116
117   gras_trp_tcp_send(sock,(char*)&myport,sizeof(uint32_t));
118   DEBUG1("peerport sent to %d", sock->peer_port);
119
120   VERB4("Connect to %s:%d (sd=%d, port %d here)",
121         sock->peer_name, sock->peer_port, sock->sd, sock->port);
122 }
123
124 /**
125  * gras_trp_sock_socket_server:
126  *
127  * Open a socket used to receive messages.
128  */
129 static inline void gras_trp_sock_socket_server(gras_trp_plugin_t ignored,
130                                                gras_socket_t sock){
131   int size = sock->buf_size; 
132   int on = 1;
133   struct sockaddr_in server;
134
135   sock->outgoing  = 1; /* TCP => duplex mode */
136
137   _gras_master_socket_port = sock->port;
138   server.sin_port = htons((u_short)sock->port);
139   server.sin_addr.s_addr = INADDR_ANY;
140   server.sin_family = AF_INET;
141   if((sock->sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
142     THROW1(system_error,0,"Socket allocation failed: %s", sock_errstr);
143
144   if (setsockopt(sock->sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)))
145      THROW1(system_error,0,"setsockopt failed, cannot condition the socket: %s",
146             sock_errstr);
147    
148   if (setsockopt(sock->sd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)) ||
149       setsockopt(sock->sd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size))) {
150      WARN1("setsockopt failed, cannot set buffer size: %s",
151            sock_errstr);
152   }
153         
154   if (bind(sock->sd, (struct sockaddr *)&server, sizeof(server)) == -1) {
155     tcp_close(sock->sd);
156     THROW2(system_error,0,"Cannot bind to port %d: %s",sock->port, sock_errstr);
157   }
158
159   DEBUG2("Listen on port %d (sd=%d)",sock->port, sock->sd);
160   if (listen(sock->sd, 5) < 0) {
161     tcp_close(sock->sd);
162     THROW2(system_error,0,"Cannot listen on port %d: %s",sock->port,sock_errstr);
163   }
164
165   VERB2("Openned a server socket on port %d (sd=%d)",sock->port,sock->sd);
166 }
167
168 static gras_socket_t gras_trp_sock_socket_accept(gras_socket_t sock) {
169   gras_socket_t res;
170   
171   struct sockaddr_in peer_in;
172   socklen_t peer_in_len = sizeof(peer_in);
173
174   int sd;
175   int tmp_errno;
176   int size;
177
178   int i = 1;
179   socklen_t s = sizeof(int);
180
181   uint32_t hisport;
182                 
183   XBT_IN;
184   gras_trp_socket_new(1,&res);
185
186   sd = accept(sock->sd, (struct sockaddr *)&peer_in, &peer_in_len);
187   tmp_errno = errno;
188
189   if (sd == -1) {
190     gras_socket_close(sock);
191     THROW1(system_error,0,
192            "Accept failed (%s). Droping server socket.", sock_errstr);
193   }
194   
195   if (setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, s) 
196       || setsockopt(sd, _gras_tcp_proto_number(), TCP_NODELAY, (char *)&i, s))
197     THROW1(system_error,0,"setsockopt failed, cannot condition the socket: %s",
198            sock_errstr);
199
200   res->buf_size = sock->buf_size;
201   size = sock->buf_size;
202   if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size))
203       || setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)))
204     WARN1("setsockopt failed, cannot set buffer size: %s", sock_errstr);
205      
206   res->plugin    = sock->plugin;
207   res->incoming  = sock->incoming;
208   res->outgoing  = sock->outgoing;
209   res->accepting = 0;
210   res->sd        = sd;
211   res->port      = -1;
212
213   gras_trp_tcp_recv(res,(char*)&hisport,sizeof(hisport));
214   res->peer_port = ntohl(hisport);
215   DEBUG1("peerport %d received",res->peer_port);
216
217   /* FIXME: Lock to protect inet_ntoa */
218   if (((struct sockaddr *)&peer_in)->sa_family != AF_INET) {
219     res->peer_name = (char*)strdup("unknown");
220   } else {
221     struct in_addr addrAsInAddr;
222     char *tmp;
223     
224     addrAsInAddr.s_addr = peer_in.sin_addr.s_addr;
225     
226     tmp = inet_ntoa(addrAsInAddr);
227     if (tmp != NULL) {
228       res->peer_name = (char*)strdup(tmp);
229     } else {
230       res->peer_name = (char*)strdup("unknown");
231     }
232   }
233   
234   VERB3("Accepted from %s:%d (sd=%d)", res->peer_name,res->peer_port,sd);
235   
236   XBT_OUT;
237   return res;
238 }
239
240 static void gras_trp_sock_socket_close(gras_socket_t sock){
241   
242   if (!sock) return; /* close only once */
243
244   VERB1("close tcp connection %d", sock->sd);
245
246   /* FIXME: no pipe in GRAS so far  
247   if(!FD_ISSET(sd, &connectedPipes)) {
248     if(shutdown(sd, 2) < 0) {
249       GetNWSLock(&lock);
250       tmp_errno = errno;
251       ReleaseNWSLock(&lock);
252       
253       / * The other side may have beaten us to the reset. * /
254       if ((tmp_errno!=ENOTCONN) && (tmp_errno!=ECONNRESET)) {
255         WARN1("CloseSocket: shutdown error %d\n", tmp_errno);
256       }
257     }
258   } */
259
260    
261   /* close the socket */
262   if(tcp_close(sock->sd) < 0) {
263     WARN3("error while closing tcp socket %d: %d (%s)\n", 
264              sock->sd, sock_errno, sock_errstr);
265   }
266
267 }
268 /************************************/
269 /****[ end of SOCKET MANAGEMENT ]****/
270 /************************************/
271
272
273 /************************************/
274 /****[ UNBUFFERED DATA EXCHANGE ]****/
275 /************************************/
276 /* Temptation to merge this with file data exchange is great, 
277    but doesn't work on BillWare (see tcp_write() in portable.h) */
278 static inline void gras_trp_tcp_send(gras_socket_t sock,
279                                      const char *data,
280                                      unsigned long int size) {
281   
282   while (size) {
283     int status = 0;
284     
285     status = tcp_write(sock->sd, data, (size_t)size);
286     DEBUG3("write(%d, %p, %ld);", sock->sd, data, size);
287     
288     if (status < 0) {
289       THROW4(system_error,0,"write(%d,%p,%ld) failed: %s",
290              sock->sd, data, size,
291              sock_errstr);
292     }
293     
294     if (status) {
295       size  -= status;
296       data  += status;
297     } else {
298       THROW1(system_error,0,"file descriptor closed (%s)",
299              sock_errstr);
300     }
301   }
302 }
303 static inline int 
304 gras_trp_tcp_recv_withbuffer(gras_socket_t sock,
305                                    char *data,
306                                    unsigned long int size,
307                                    unsigned long int bufsize) {
308
309   int got = 0;
310
311   while (size>got) {
312     int status = 0;
313     
314     DEBUG5("read(%d, %p, %ld) got %d so far (%s)",
315           sock->sd, data+got, bufsize, got,
316           hexa_str((unsigned char*)data,got));
317     status = tcp_read(sock->sd, data+got, (size_t)bufsize);
318     
319     if (status < 0) {
320       THROW7(system_error,0,"read(%d,%p,%d) from %s:%d failed: %s; got %d so far",
321              sock->sd, data+got, (int)size,
322              gras_socket_peer_name(sock),gras_socket_peer_port(sock),
323              sock_errstr,
324              got);
325     }
326     DEBUG2("Got %d more bytes (%s)",status,hexa_str((unsigned char*)data+got,status));
327     
328     if (status) {
329       bufsize -= status;
330       got     += status;
331     } else {
332       THROW1(system_error,0,"Socket closed by remote side (got %d bytes before this)",
333              got);
334     }
335   }
336   return got;
337 }
338
339 static int gras_trp_tcp_recv(gras_socket_t sock,
340                                    char *data,
341                                    unsigned long int size) {
342   return gras_trp_tcp_recv_withbuffer(sock,data,size,size);
343
344 }
345 /*******************************************/
346 /****[ end of UNBUFFERED DATA EXCHANGE ]****/
347 /*******************************************/
348
349 /**********************************/
350 /****[ BUFFERED DATA EXCHANGE ]****/
351 /**********************************/
352
353 /* Make sure the data is sent */
354 static void
355 gras_trp_bufiov_flush(gras_socket_t sock) {
356 #ifdef HAVE_READV
357   xbt_dynar_t vect;
358   int size;
359 #endif
360   gras_trp_bufdata_t *data=sock->bufdata;
361   XBT_IN;    
362   
363   DEBUG0("Flush");
364   if (data->out == buffering_buf) {
365     if (XBT_LOG_ISENABLED(gras_trp_tcp,xbt_log_priority_debug))
366       hexa_print("chunk to send ",
367                  (unsigned char *) data->out_buf.data,data->out_buf.size);
368     if ((data->out_buf.size - data->out_buf.pos) != 0) { 
369       DEBUG3("Send the chunk (size=%d) to %s:%d",data->out_buf.size,
370              gras_socket_peer_name(sock),gras_socket_peer_port(sock));
371       gras_trp_tcp_send(sock, data->out_buf.data, data->out_buf.size);
372       VERB1("Chunk sent (size=%d)",data->out_buf.size);
373       data->out_buf.size = 0;
374     }
375   }
376
377 #ifdef HAVE_READV
378   if (data->out == buffering_iov) {
379     DEBUG0("Flush out iov");
380     vect = sock->bufdata->out_buf_v;
381     if ((size = xbt_dynar_length(vect))) {
382       DEBUG1("Flush %d chunks out of this socket",size);
383       writev(sock->sd,xbt_dynar_get_ptr(vect,0),size);
384       xbt_dynar_reset(vect);
385     }
386     data->out_buf.size = 0; /* reset the buffer containing non-stable data */
387   }
388
389   if (data->in == buffering_iov) {
390     DEBUG0("Flush in iov");
391     vect = sock->bufdata->in_buf_v;
392     if ((size = xbt_dynar_length(vect))) {
393       DEBUG1("Get %d chunks from of this socket",size);
394       readv(sock->sd,xbt_dynar_get_ptr(vect,0),size);
395       xbt_dynar_reset(vect);
396     }
397   }
398 #endif
399 }
400 static void
401 gras_trp_buf_send(gras_socket_t sock,
402                   const char *chunk,
403                   unsigned long int size,
404                   int stable_ignored) {
405
406   gras_trp_bufdata_t *data=(gras_trp_bufdata_t*)sock->bufdata;
407   int chunk_pos=0;
408
409   XBT_IN;
410
411   while (chunk_pos < size) {
412     /* size of the chunk to receive in that shot */
413     long int thissize = min(size-chunk_pos,data->buffsize-data->out_buf.size);
414     DEBUG4("Set the chars %d..%ld into the buffer; size=%ld, ctn=(%s)",
415            (int)data->out_buf.size,
416            ((int)data->out_buf.size) + thissize -1,
417            size,
418            hexa_str((unsigned char*)chunk,thissize));
419
420     memcpy(data->out_buf.data + data->out_buf.size, chunk + chunk_pos, thissize);
421
422     data->out_buf.size += thissize;
423     chunk_pos      += thissize;
424     DEBUG4("New pos = %d; Still to send = %ld of %ld; ctn sofar=(%s)",
425            data->out_buf.size,size-chunk_pos,size,hexa_str((unsigned char*)chunk,chunk_pos));
426
427     if (data->out_buf.size == data->buffsize) /* out of space. Flush it */
428       gras_trp_bufiov_flush(sock);
429   }
430
431   XBT_OUT;
432 }
433
434 static int
435 gras_trp_buf_recv(gras_socket_t sock,
436                   char *chunk,
437                   unsigned long int size) {
438
439   gras_trp_bufdata_t *data=sock->bufdata;
440   long int chunk_pos = 0;
441    
442   XBT_IN;
443
444   while (chunk_pos < size) {
445     /* size of the chunk to receive in that shot */
446     long int thissize;
447
448     if (data->in_buf.size == data->in_buf.pos) { /* out of data. Get more */
449
450       DEBUG2("Get more data (size=%d,bufsize=%d)",
451              (int)MIN(size-chunk_pos,data->buffsize),
452              (int)data->buffsize);
453
454        
455       data->in_buf.size = 
456         gras_trp_tcp_recv_withbuffer(sock, data->in_buf.data, 
457                                      MIN(size-chunk_pos,data->buffsize),
458                                      data->buffsize);
459        
460       data->in_buf.pos=0;
461     }
462      
463     thissize = min(size-chunk_pos ,  data->in_buf.size - data->in_buf.pos);
464     memcpy(chunk+chunk_pos, data->in_buf.data + data->in_buf.pos, thissize);
465
466     data->in_buf.pos += thissize;
467     chunk_pos        += thissize;
468     DEBUG4("New pos = %d; Still to receive = %ld of %ld. Ctn so far=(%s)",
469            data->in_buf.pos,size - chunk_pos,size,hexa_str((unsigned char*)chunk,chunk_pos));
470   }
471
472   XBT_OUT;
473   return chunk_pos;
474 }
475
476 /*****************************************/
477 /****[ end of BUFFERED DATA EXCHANGE ]****/
478 /*****************************************/
479
480 /********************************/
481 /****[ VECTOR DATA EXCHANGE ]****/
482 /********************************/
483 #ifdef HAVE_READV
484 static void
485 gras_trp_iov_send(gras_socket_t sock,
486                   const char *chunk,
487                   unsigned long int size,
488                   int stable) {
489   struct iovec elm;
490   gras_trp_bufdata_t *data=(gras_trp_bufdata_t*)sock->bufdata;
491     
492
493   DEBUG1("Buffer one chunk to be sent later (%s)",
494         hexa_str((char*)chunk,size));
495
496   elm.iov_len = (size_t)size;
497
498   if (!stable) {
499     /* data storage won't last until flush. Save it in a buffer if we can */
500
501     if (size > data->buffsize-data->out_buf.size) {
502       /* buffer too small: 
503          flush the socket, using data in its actual storage */
504       elm.iov_base = (void*)chunk;
505       xbt_dynar_push(data->out_buf_v,&elm);
506
507       gras_trp_bufiov_flush(sock);      
508       return;
509     } else {
510       /* buffer big enough: 
511          copy data into it, and chain it for upcoming writev */
512       memcpy(data->out_buf.data + data->out_buf.size, chunk, size);
513       elm.iov_base = (void*)(data->out_buf.data + data->out_buf.size);
514       data->out_buf.size += size;
515
516       xbt_dynar_push(data->out_buf_v,&elm);
517     }
518
519   } else {
520     /* data storage stable. Chain it */
521     
522     elm.iov_base = (void*)chunk;
523     xbt_dynar_push(data->out_buf_v,&elm);
524   }
525 }
526 static int
527 gras_trp_iov_recv(gras_socket_t sock,
528                   char *chunk,
529                   unsigned long int size) {
530   struct iovec elm;
531
532   DEBUG0("Buffer one chunk to be received later");
533   elm.iov_base = (void*)chunk;
534   elm.iov_len = (size_t)size;
535   xbt_dynar_push(sock->bufdata->in_buf_v,&elm);
536
537   return size;
538 }
539
540 #endif
541 /***************************************/
542 /****[ end of VECTOR DATA EXCHANGE ]****/
543 /***************************************/
544
545
546 /***
547  *** Prototypes of BUFFERED
548  ***/
549    
550 void gras_trp_buf_socket_client(gras_trp_plugin_t self,
551                                 gras_socket_t sock);
552 void gras_trp_buf_socket_server(gras_trp_plugin_t self,
553                                 gras_socket_t sock);
554 gras_socket_t gras_trp_buf_socket_accept(gras_socket_t sock);
555
556 void         gras_trp_buf_socket_close(gras_socket_t sd);
557   
558
559 gras_socket_t gras_trp_buf_init_sock(gras_socket_t sock) {
560   gras_trp_bufdata_t *data=xbt_new(gras_trp_bufdata_t,1);
561   
562   data->buffsize = 100 * 1024 ; /* 100k */ 
563
564   data->in_buf.size  = 0;
565   data->in_buf.data  = xbt_malloc(data->buffsize);
566   data->in_buf.pos   = 0; /* useless, indeed, since size==pos */
567    
568   data->out_buf.size = 0;
569   data->out_buf.data = xbt_malloc(data->buffsize);
570   data->out_buf.pos  = data->out_buf.size;
571
572 #ifdef HAVE_READV
573   data->in_buf_v = data->out_buf_v = NULL;
574   data->in_buf_v=xbt_dynar_new(sizeof(struct iovec),NULL);
575   data->out_buf_v=xbt_dynar_new(sizeof(struct iovec),NULL);
576   data->out = buffering_iov;
577 #else
578   data->out = buffering_buf;
579 #endif
580    
581   data->in = buffering_buf;
582
583   sock->bufdata = data;
584   return sock;
585 }
586
587 /***
588  *** Code
589  ***/
590 void
591 gras_trp_tcp_setup(gras_trp_plugin_t plug) {
592
593   plug->socket_client = gras_trp_buf_socket_client;
594   plug->socket_server = gras_trp_buf_socket_server;
595   plug->socket_accept = gras_trp_buf_socket_accept;
596   plug->socket_close  = gras_trp_buf_socket_close;
597
598 #ifdef HAVE_READV
599   plug->send = gras_trp_iov_send;
600 #else
601   plug->send = gras_trp_buf_send;
602 #endif
603   plug->recv = gras_trp_buf_recv;
604
605   plug->raw_send    = gras_trp_tcp_send;
606   plug->raw_recv    = gras_trp_tcp_recv;
607
608   plug->flush         = gras_trp_bufiov_flush;
609
610   plug->data = NULL;
611   plug->exit = NULL;
612 }
613
614 void gras_trp_buf_socket_client(gras_trp_plugin_t self,
615                                 /* OUT */ gras_socket_t sock){
616
617   gras_trp_sock_socket_client(NULL,sock);
618   gras_trp_buf_init_sock(sock);
619 }
620
621 /**
622  * gras_trp_buf_socket_server:
623  *
624  * Open a socket used to receive messages.
625  */
626 void gras_trp_buf_socket_server(gras_trp_plugin_t self,
627                                 /* OUT */ gras_socket_t sock){
628
629   gras_trp_sock_socket_server(NULL,sock);
630   gras_trp_buf_init_sock(sock);
631 }
632
633 gras_socket_t gras_trp_buf_socket_accept(gras_socket_t sock) {
634   return gras_trp_buf_init_sock(gras_trp_sock_socket_accept(sock));
635 }
636
637 void gras_trp_buf_socket_close(gras_socket_t sock){
638   gras_trp_bufdata_t *data=sock->bufdata;
639
640   if (data->in_buf.size!=data->in_buf.pos) {
641      WARN3("Socket closed, but %d bytes were unread (size=%d,pos=%d)",
642            data->in_buf.size - data->in_buf.pos,
643            data->in_buf.size, data->in_buf.pos);
644   }
645   if (data->in_buf.data)
646     free(data->in_buf.data);
647    
648   if (data->out_buf.size!=data->out_buf.pos) {
649     DEBUG2("Flush the socket before closing (in=%d,out=%d)",
650            data->in_buf.size, data->out_buf.size);
651     gras_trp_bufiov_flush(sock);
652   }   
653   if (data->out_buf.data)
654     free(data->out_buf.data);
655
656 #ifdef HAVE_READV
657   if (data->in_buf_v) {
658     if (xbt_dynar_length(data->in_buf_v)) 
659       WARN0("Socket closed, but some bytes were unread");
660     xbt_dynar_free(&data->in_buf_v);
661   }
662   if (data->out_buf_v) {
663     if (xbt_dynar_length(data->out_buf_v)) {
664       DEBUG0("Flush the socket before closing");
665       gras_trp_bufiov_flush(sock);
666     }
667     xbt_dynar_free(&data->out_buf_v);
668   }
669 #endif
670
671   free(data);
672   gras_trp_sock_socket_close(sock);
673 }
674
675 /****************************/
676 /****[ HELPER FUNCTIONS ]****/
677 /****************************/
678
679 /*
680  * Returns the tcp protocol number from the network protocol data base.
681  *
682  * getprotobyname() is not thread safe. We need to lock it.
683  */
684 static int _gras_tcp_proto_number(void) {
685   struct protoent *fetchedEntry;
686   static int returnValue = 0;
687   
688   if(returnValue == 0) {
689     fetchedEntry = getprotobyname("tcp");
690     xbt_assert0(fetchedEntry, "getprotobyname(tcp) gave NULL");
691     returnValue = fetchedEntry->p_proto;
692   }
693   
694   return returnValue;
695 }
696
697 #ifdef HAVE_WINSOCK_H
698 #define RETSTR( x ) case x: return #x
699
700 const char *gras_wsa_err2string( int err ) {
701    switch( err ) {
702       RETSTR( WSAEINTR );
703       RETSTR( WSAEBADF );
704       RETSTR( WSAEACCES );
705       RETSTR( WSAEFAULT );
706       RETSTR( WSAEINVAL );
707       RETSTR( WSAEMFILE );
708       RETSTR( WSAEWOULDBLOCK );
709       RETSTR( WSAEINPROGRESS );
710       RETSTR( WSAEALREADY );
711       RETSTR( WSAENOTSOCK );
712       RETSTR( WSAEDESTADDRREQ );
713       RETSTR( WSAEMSGSIZE );
714       RETSTR( WSAEPROTOTYPE );
715       RETSTR( WSAENOPROTOOPT );
716       RETSTR( WSAEPROTONOSUPPORT );
717       RETSTR( WSAESOCKTNOSUPPORT );
718       RETSTR( WSAEOPNOTSUPP );
719       RETSTR( WSAEPFNOSUPPORT );
720       RETSTR( WSAEAFNOSUPPORT );
721       RETSTR( WSAEADDRINUSE );
722       RETSTR( WSAEADDRNOTAVAIL );
723       RETSTR( WSAENETDOWN );
724       RETSTR( WSAENETUNREACH );
725       RETSTR( WSAENETRESET );
726       RETSTR( WSAECONNABORTED );
727       RETSTR( WSAECONNRESET );
728       RETSTR( WSAENOBUFS );
729       RETSTR( WSAEISCONN );
730       RETSTR( WSAENOTCONN );
731       RETSTR( WSAESHUTDOWN );
732       RETSTR( WSAETOOMANYREFS );
733       RETSTR( WSAETIMEDOUT );
734       RETSTR( WSAECONNREFUSED );
735       RETSTR( WSAELOOP );
736       RETSTR( WSAENAMETOOLONG );
737       RETSTR( WSAEHOSTDOWN );
738       RETSTR( WSAEHOSTUNREACH );
739       RETSTR( WSAENOTEMPTY );
740       RETSTR( WSAEPROCLIM );
741       RETSTR( WSAEUSERS );
742       RETSTR( WSAEDQUOT );
743       RETSTR( WSAESTALE );
744       RETSTR( WSAEREMOTE );
745       RETSTR( WSASYSNOTREADY );
746       RETSTR( WSAVERNOTSUPPORTED );
747       RETSTR( WSANOTINITIALISED );
748       RETSTR( WSAEDISCON );
749       
750 #ifdef HAVE_WINSOCK2
751       RETSTR( WSAENOMORE );
752       RETSTR( WSAECANCELLED );
753       RETSTR( WSAEINVALIDPROCTABLE );
754       RETSTR( WSAEINVALIDPROVIDER );
755       RETSTR( WSASYSCALLFAILURE );
756       RETSTR( WSASERVICE_NOT_FOUND );
757       RETSTR( WSATYPE_NOT_FOUND );
758       RETSTR( WSA_E_NO_MORE );
759       RETSTR( WSA_E_CANCELLED );
760       RETSTR( WSAEREFUSED );
761 #endif /* HAVE_WINSOCK2 */
762
763       RETSTR( WSAHOST_NOT_FOUND );
764       RETSTR( WSATRY_AGAIN );
765       RETSTR( WSANO_RECOVERY );
766       RETSTR( WSANO_DATA );
767    }
768    return "unknown WSA error";
769 }
770 #endif /* HAVE_WINSOCK_H */
771
772 /***********************************/
773 /****[ end of HELPER FUNCTIONS ]****/
774 /***********************************/