1 /***************************************************************************
2     begin       : Tue Oct 02 2002
3     copyright   : (C) 2002 by Martin Preuss
4     email       : martin@libchipcard.de
5 
6  ***************************************************************************
7  *                                                                         *
8  *   This library is free software; you can redistribute it and/or         *
9  *   modify it under the terms of the GNU Lesser General Public            *
10  *   License as published by the Free Software Foundation; either          *
11  *   version 2.1 of the License, or (at your option) any later version.    *
12  *                                                                         *
13  *   This library is distributed in the hope that it will be useful,       *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
16  *   Lesser General Public License for more details.                       *
17  *                                                                         *
18  *   You should have received a copy of the GNU Lesser General Public      *
19  *   License along with this library; if not, write to the Free Software   *
20  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
21  *   MA  02111-1307  USA                                                   *
22  *                                                                         *
23  ***************************************************************************/
24 
25 
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29 
30 
31 
32 #include "inetsocket_p.h"
33 #include "inetaddr_p.h"
34 #include "errorstring.h"
35 #include <gwenhywfar/misc.h>
36 #include <gwenhywfar/debug.h>
37 
38 #include <errno.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <sys/time.h>
44 
45 
46 
47 GWEN_LIST_FUNCTIONS(GWEN_SOCKET, GWEN_Socket)
48 GWEN_LIST2_FUNCTIONS(GWEN_SOCKET, GWEN_Socket)
49 
50 
51 static int gwen_socket_is_initialized=0;
52 
53 
54 
GWEN_Socket_ModuleInit(void)55 int GWEN_Socket_ModuleInit(void)
56 {
57   WORD wVersionRequested;
58   WSADATA wsaData;
59 
60   if (!gwen_socket_is_initialized) {
61     int rv;
62 
63     /* setup WINSOCK (request version 1.1) */
64     wVersionRequested=MAKEWORD(1, 1);
65     rv=WSAStartup(wVersionRequested, &wsaData);
66     if (rv) {
67       DBG_INFO(GWEN_LOGDOMAIN, "Error on WSAStartup");
68       return rv;
69     }
70     /* check if the version returned is that we requested */
71     if (LOBYTE(wsaData.wVersion)!=1 ||
72         HIBYTE(wsaData.wVersion)!=1) {
73       WSACleanup();
74       return GWEN_ERROR_STARTUP;
75     }
76 
77     gwen_socket_is_initialized=1;
78   }
79   return 0;
80 }
81 
82 
83 
GWEN_Socket_ModuleFini(void)84 int GWEN_Socket_ModuleFini(void)
85 {
86   if (gwen_socket_is_initialized) {
87 
88     WSACleanup();
89 
90     gwen_socket_is_initialized=0;
91   }
92   return 0;
93 }
94 
95 
96 
GWEN_SocketSet_Clear(GWEN_SOCKETSET * ssp)97 int GWEN_SocketSet_Clear(GWEN_SOCKETSET *ssp)
98 {
99   assert(ssp);
100   FD_ZERO(&(ssp->set));
101   ssp->highest=0;
102   return 0;
103 }
104 
105 
106 
GWEN_SocketSet_new(void)107 GWEN_SOCKETSET *GWEN_SocketSet_new(void)
108 {
109   GWEN_SOCKETSET *ssp;
110 
111   GWEN_NEW_OBJECT(GWEN_SOCKETSET, ssp);
112   FD_ZERO(&(ssp->set));
113   return ssp;
114 }
115 
116 
117 
GWEN_Socket_fromFile(int fd)118 GWEN_SOCKET *GWEN_Socket_fromFile(int fd)
119 {
120   DBG_ERROR(GWEN_LOGDOMAIN,
121             "No file sockets available for this system");
122   return 0;
123 }
124 
125 
126 
GWEN_SocketSet_free(GWEN_SOCKETSET * ssp)127 void GWEN_SocketSet_free(GWEN_SOCKETSET *ssp)
128 {
129   if (ssp) {
130     FD_ZERO(&(ssp->set));
131     GWEN_FREE_OBJECT(ssp);
132   }
133 }
134 
135 
136 
GWEN_SocketSet_AddSocket(GWEN_SOCKETSET * ssp,const GWEN_SOCKET * sp)137 int GWEN_SocketSet_AddSocket(GWEN_SOCKETSET *ssp,
138                              const GWEN_SOCKET *sp)
139 {
140   assert(ssp);
141   assert(sp);
142   if (sp->socket==-1) {
143     DBG_INFO(GWEN_LOGDOMAIN, "Socket is not connected, can not add");
144     return GWEN_ERROR_NOT_OPEN;
145   }
146   ssp->highest=(ssp->highest<sp->socket)?sp->socket:ssp->highest;
147   FD_SET(sp->socket, &(ssp->set));
148   ssp->count++;
149   return 0;
150 }
151 
152 
153 
GWEN_SocketSet_RemoveSocket(GWEN_SOCKETSET * ssp,const GWEN_SOCKET * sp)154 int GWEN_SocketSet_RemoveSocket(GWEN_SOCKETSET *ssp,
155                                 const GWEN_SOCKET *sp)
156 {
157   assert(ssp);
158   assert(sp);
159   ssp->highest=(ssp->highest<sp->socket)?sp->socket:ssp->highest;
160   FD_CLR(sp->socket, &(ssp->set));
161   ssp->count--;
162   return 0;
163 }
164 
165 
166 
GWEN_SocketSet_HasSocket(GWEN_SOCKETSET * ssp,const GWEN_SOCKET * sp)167 int GWEN_SocketSet_HasSocket(GWEN_SOCKETSET *ssp,
168                              const GWEN_SOCKET *sp)
169 {
170   assert(ssp);
171   assert(sp);
172   return FD_ISSET(sp->socket, &(ssp->set));
173 }
174 
175 
176 
GWEN_SocketSet_GetSocketCount(GWEN_SOCKETSET * ssp)177 int GWEN_SocketSet_GetSocketCount(GWEN_SOCKETSET *ssp)
178 {
179   assert(ssp);
180   return ssp->count;
181 }
182 
183 
184 
185 
186 
GWEN_Socket_new(GWEN_SOCKETTYPE socketType)187 GWEN_SOCKET *GWEN_Socket_new(GWEN_SOCKETTYPE socketType)
188 {
189   GWEN_SOCKET *sp;
190 
191   GWEN_NEW_OBJECT(GWEN_SOCKET, sp);
192   GWEN_LIST_INIT(GWEN_SOCKET, sp);
193   sp->type=socketType;
194   return sp;
195 }
196 
197 
198 
GWEN_Socket_free(GWEN_SOCKET * sp)199 void GWEN_Socket_free(GWEN_SOCKET *sp)
200 {
201   if (sp) {
202     GWEN_LIST_FINI(GWEN_SOCKET, sp);
203     GWEN_FREE_OBJECT(sp);
204   }
205 }
206 
207 
208 
GWEN_Socket_Open(GWEN_SOCKET * sp)209 int GWEN_Socket_Open(GWEN_SOCKET *sp)
210 {
211   int s;
212 
213   assert(sp);
214   switch (sp->type) {
215   case GWEN_SocketTypeTCP:
216 #ifdef PF_INET
217     s=socket(PF_INET, SOCK_STREAM, 0);
218 #else
219     s=socket(AF_INET, SOCK_STREAM, 0);
220 #endif
221     if (s==-1)
222       return WSAGetLastError();
223     sp->socket=s;
224     break;
225 
226   case GWEN_SocketTypeUDP:
227 #ifdef PF_INET
228     s=socket(PF_INET, SOCK_DGRAM, 0);
229 #else
230     s=socket(AF_INET, SOCK_DGRAM, 0);
231 #endif
232     if (s==-1)
233       return WSAGetLastError();
234     sp->socket=s;
235     break;
236 
237   case GWEN_SocketTypeUnix:
238     DBG_ERROR(GWEN_LOGDOMAIN, "No unix domain sockets available for this system");
239     return GWEN_ERROR_BAD_ADDRESS_FAMILY;
240     break;
241 
242   default:
243     return GWEN_ERROR_BAD_SOCKETTYPE;
244   } /* switch */
245 
246   return 0;
247 }
248 
249 
250 
GWEN_Socket_Connect(GWEN_SOCKET * sp,const GWEN_INETADDRESS * addr)251 int GWEN_Socket_Connect(GWEN_SOCKET *sp,
252                         const GWEN_INETADDRESS *addr)
253 {
254   assert(sp);
255   if (connect(sp->socket,
256               addr->address,
257               addr->size)) {
258     if (WSAGetLastError()!=WSAEINPROGRESS &&
259         WSAGetLastError()!=WSAEWOULDBLOCK) {
260       DBG_INFO(GWEN_LOGDOMAIN, "Error %d (%s)",
261                WSAGetLastError(),
262                GWEN_ErrorString_Windows(WSAGetLastError()));
263       return WSAGetLastError();
264     }
265     else
266       return GWEN_ERROR_IN_PROGRESS;
267   }
268   return 0;
269 }
270 
271 
272 
GWEN_Socket_Close(GWEN_SOCKET * sp)273 int GWEN_Socket_Close(GWEN_SOCKET *sp)
274 {
275   int rv;
276 
277   assert(sp);
278   if (sp->socket==-1)
279     return GWEN_ERROR_NOT_OPEN;
280 
281   rv=closesocket(sp->socket);
282   sp->socket=-1;
283   if (rv==-1)
284     return WSAGetLastError();
285   return 0;
286 }
287 
288 
289 
GWEN_Socket_Bind(GWEN_SOCKET * sp,const GWEN_INETADDRESS * addr)290 int GWEN_Socket_Bind(GWEN_SOCKET *sp,
291                      const GWEN_INETADDRESS *addr)
292 {
293   assert(sp);
294   assert(addr);
295   if (bind(sp->socket,
296            addr->address,
297            addr->size))
298     return WSAGetLastError();
299   return 0;
300 }
301 
302 
303 
GWEN_Socket_Listen(GWEN_SOCKET * sp,int backlog)304 int GWEN_Socket_Listen(GWEN_SOCKET *sp, int backlog)
305 {
306   assert(sp);
307   if (listen(sp->socket, backlog))
308     return WSAGetLastError();
309   return 0;
310 }
311 
312 
313 
GWEN_Socket_Accept(GWEN_SOCKET * sp,GWEN_INETADDRESS ** newaddr,GWEN_SOCKET ** newsock)314 int GWEN_Socket_Accept(GWEN_SOCKET *sp,
315                        GWEN_INETADDRESS **newaddr,
316                        GWEN_SOCKET **newsock)
317 {
318   int addrlen;
319   GWEN_INETADDRESS *localAddr;
320   GWEN_SOCKET *localSocket;
321   GWEN_AddressFamily af;
322 
323   assert(sp);
324   assert(newsock);
325   assert(newaddr);
326 
327   switch (sp->type) {
328   case GWEN_SocketTypeTCP:
329   case GWEN_SocketTypeUDP:
330     af=GWEN_AddressFamilyIP;
331     break;
332   case GWEN_SocketTypeUnix:
333     af=GWEN_AddressFamilyUnix;
334     break;
335   default:
336     return GWEN_ERROR_BAD_SOCKETTYPE;
337   } /* switch */
338 
339   localAddr=GWEN_InetAddr_new(af);
340   addrlen=localAddr->size;
341   localSocket=GWEN_Socket_new(sp->type);
342   localSocket->socket=accept(sp->socket,
343                              localAddr->address,
344                              &addrlen);
345   if (localSocket->socket==-1) {
346     GWEN_InetAddr_free(localAddr);
347     GWEN_Socket_free(localSocket);
348     if (WSAGetLastError()==WSAEWOULDBLOCK)
349       return GWEN_ERROR_TIMEOUT;
350     else
351       return WSAGetLastError();
352   }
353   localSocket->type=sp->type;
354   localAddr->size=addrlen;
355   *newaddr=localAddr;
356   *newsock=localSocket;
357   return 0;
358 }
359 
360 
361 
GWEN_Socket_GetPeerAddr(GWEN_SOCKET * sp,GWEN_INETADDRESS ** newaddr)362 int GWEN_Socket_GetPeerAddr(GWEN_SOCKET *sp,
363                             GWEN_INETADDRESS **newaddr)
364 {
365   int addrlen;
366   GWEN_INETADDRESS *localAddr;
367   GWEN_AddressFamily af;
368 
369   assert(sp);
370   assert(newaddr);
371 
372   switch (sp->type) {
373   case GWEN_SocketTypeTCP:
374   case GWEN_SocketTypeUDP:
375     af=GWEN_AddressFamilyIP;
376     break;
377   case GWEN_SocketTypeUnix:
378     af=GWEN_AddressFamilyUnix;
379     break;
380   default:
381     return GWEN_ERROR_BAD_SOCKETTYPE;
382   } /* switch */
383 
384   localAddr=GWEN_InetAddr_new(af);
385   addrlen=localAddr->size;
386 
387   if (getpeername(sp->socket,
388                   localAddr->address, &addrlen)) {
389     GWEN_InetAddr_free(localAddr);
390     return WSAGetLastError();
391   }
392   localAddr->size=addrlen;
393   *newaddr=localAddr;
394   return 0;
395 }
396 
397 
398 
GWEN_Socket_Select(GWEN_SOCKETSET * rs,GWEN_SOCKETSET * ws,GWEN_SOCKETSET * xs,int timeout)399 int GWEN_Socket_Select(GWEN_SOCKETSET *rs,
400                        GWEN_SOCKETSET *ws,
401                        GWEN_SOCKETSET *xs,
402                        int timeout)
403 {
404   int h, h1, h2, h3;
405   fd_set *s1, *s2, *s3;
406   int rv;
407   struct timeval tv;
408 
409   s1=s2=s3=0;
410   h1=h2=h3=0;
411 
412   if (rs) {
413     h1=rs->highest;
414     s1=&rs->set;
415   }
416   if (ws) {
417     h2=ws->highest;
418     s2=&ws->set;
419   }
420   if (xs) {
421     h3=xs->highest;
422     s3=&xs->set;
423   }
424   h=(h1>h2)?h1:h2;
425   h=(h>h3)?h:h3;
426   if (timeout<0)
427     /* wait for ever */
428     rv=select(h+1, s1, s2, s3, 0);
429   else {
430     /* return immediately */
431     tv.tv_sec=0;
432     tv.tv_usec=timeout*1000;
433     rv=select(h+1, s1, s2, s3, &tv);
434   }
435   if (rv<0) {
436     /* error */
437     if (WSAGetLastError()==WSAEINTR)
438       return GWEN_ERROR_INTERRUPTED;
439     else
440       return WSAGetLastError();
441   }
442   if (rv==0)
443     /* timeout */
444     return GWEN_ERROR_TIMEOUT;
445   return 0;
446 }
447 
448 
449 
GWEN_Socket_Read(GWEN_SOCKET * sp,char * buffer,int * bsize)450 int GWEN_Socket_Read(GWEN_SOCKET *sp,
451                      char *buffer,
452                      int *bsize)
453 {
454   int i;
455 
456   assert(sp);
457   assert(buffer);
458   assert(bsize);
459   i=recv(sp->socket, buffer, *bsize, 0);
460   if (i<0) {
461     if (WSAGetLastError()==WSAEWOULDBLOCK)
462       return GWEN_ERROR_TIMEOUT;
463     else if (WSAGetLastError()==WSAEINTR)
464       return GWEN_ERROR_INTERRUPTED;
465     else
466       return WSAGetLastError();
467   }
468   *bsize=i;
469   return 0;
470 }
471 
472 
473 
GWEN_Socket_Write(GWEN_SOCKET * sp,const char * buffer,int * bsize)474 int GWEN_Socket_Write(GWEN_SOCKET *sp,
475                       const char *buffer,
476                       int *bsize)
477 {
478   int i;
479 
480   assert(sp);
481   assert(buffer);
482   assert(bsize);
483 #ifndef MSG_NOSIGNAL
484   i=send(sp->socket, buffer, *bsize, 0);
485 #else
486   i=send(sp->socket, buffer, *bsize, MSG_NOSIGNAL);
487 #endif
488   if (i<0) {
489     if (WSAGetLastError()==WSAEWOULDBLOCK)
490       return GWEN_ERROR_TIMEOUT;
491     else if (WSAGetLastError()==WSAEINTR)
492       return GWEN_ERROR_INTERRUPTED;
493     else
494       return WSAGetLastError();
495   }
496   *bsize=i;
497   return 0;
498 }
499 
500 
501 
GWEN_Socket_ReadFrom(GWEN_SOCKET * sp,GWEN_INETADDRESS ** newaddr,char * buffer,int * bsize)502 int GWEN_Socket_ReadFrom(GWEN_SOCKET *sp,
503                          GWEN_INETADDRESS **newaddr,
504                          char *buffer,
505                          int *bsize)
506 {
507   int addrlen;
508   int i;
509   GWEN_INETADDRESS *localAddr;
510   GWEN_AddressFamily af;
511 
512   assert(sp);
513   assert(newaddr);
514   assert(buffer);
515   assert(bsize);
516 
517   switch (sp->type) {
518   case GWEN_SocketTypeTCP:
519   case GWEN_SocketTypeUDP:
520     af=GWEN_AddressFamilyIP;
521     break;
522   case GWEN_SocketTypeUnix:
523     af=GWEN_AddressFamilyUnix;
524     break;
525   default:
526     return GWEN_ERROR_BAD_SOCKETTYPE;
527   } /* switch */
528 
529   localAddr=GWEN_InetAddr_new(af);
530   addrlen=localAddr->size;
531 
532   i=recvfrom(sp->socket,
533              buffer,
534              *bsize,
535              0,
536              localAddr->address,
537              &addrlen);
538   if (i<0) {
539     GWEN_InetAddr_free(localAddr);
540     if (WSAGetLastError()==WSAEWOULDBLOCK)
541       return GWEN_ERROR_TIMEOUT;
542     else if (WSAGetLastError()==WSAEINTR)
543       return GWEN_ERROR_INTERRUPTED;
544     else
545       return WSAGetLastError();
546   }
547   *bsize=i;
548   localAddr->size=addrlen;
549   *newaddr=localAddr;
550   return 0;
551 }
552 
553 
554 
GWEN_Socket_WriteTo(GWEN_SOCKET * sp,const GWEN_INETADDRESS * addr,const char * buffer,int * bsize)555 int GWEN_Socket_WriteTo(GWEN_SOCKET *sp,
556                         const GWEN_INETADDRESS *addr,
557                         const char *buffer,
558                         int *bsize)
559 {
560   int i;
561 
562   assert(sp);
563   assert(addr);
564   assert(buffer);
565   assert(bsize);
566   i=sendto(sp->socket,
567            buffer,
568            *bsize,
569 #ifndef MSG_NOSIGNAL
570            0,
571 #else
572            MSG_NOSIGNAL,
573 #endif
574            addr->address,
575            addr->size);
576   if (i<0) {
577     if (WSAGetLastError()==WSAEWOULDBLOCK)
578       return GWEN_ERROR_TIMEOUT;
579     else if (WSAGetLastError()==WSAEINTR)
580       return GWEN_ERROR_INTERRUPTED;
581     else
582       return WSAGetLastError();
583   }
584   *bsize=i;
585   return 0;
586 }
587 
588 
589 
GWEN_Socket_SetBlocking(GWEN_SOCKET * sp,int b)590 int GWEN_Socket_SetBlocking(GWEN_SOCKET *sp,
591                             int b)
592 {
593   unsigned long fl;
594 
595   assert(sp);
596   fl=!b;
597   if (ioctlsocket(sp->socket, FIONBIO, &fl)) {
598     DBG_INFO(GWEN_LOGDOMAIN, "Error %d (%s)",
599              WSAGetLastError(),
600              GWEN_ErrorString_Windows(WSAGetLastError()));
601     return WSAGetLastError();
602   }
603   return 0;
604 }
605 
606 
607 
GWEN_Socket_SetBroadcast(GWEN_SOCKET * sp,int fl)608 int GWEN_Socket_SetBroadcast(GWEN_SOCKET *sp,
609                              int fl)
610 {
611 
612   assert(sp);
613   if (sp->type==GWEN_SocketTypeUnix)
614     return 0;
615   if (setsockopt(sp->socket,
616                  SOL_SOCKET,
617                  SO_BROADCAST,
618                  (const char *)&fl,
619                  sizeof(fl)))
620     return WSAGetLastError();
621   return 0;
622 }
623 
624 
625 
GWEN_Socket_SetReuseAddress(GWEN_SOCKET * sp,int fl)626 int GWEN_Socket_SetReuseAddress(GWEN_SOCKET *sp, int fl)
627 {
628   assert(sp);
629 
630   /*if (sp->type==SocketTypeUnix)
631     return 0;*/
632 
633   if (setsockopt(sp->socket,
634                  SOL_SOCKET,
635                  SO_REUSEADDR,
636                  (const char *)&fl,
637                  sizeof(fl)))
638     return WSAGetLastError();
639   return 0;
640 }
641 
642 
643 
GWEN_Socket_GetSocketError(GWEN_SOCKET * sp)644 int GWEN_Socket_GetSocketError(GWEN_SOCKET *sp)
645 {
646   int rv;
647   int rvs;
648 
649   assert(sp);
650   rvs=sizeof(rv);
651   if (-1==getsockopt(sp->socket, SOL_SOCKET, SO_ERROR, (char *)&rv, &rvs)) {
652     DBG_INFO(GWEN_LOGDOMAIN, "getsockopt(): %s", GWEN_ErrorString_Windows(WSAGetLastError()));
653     return GWEN_ERROR_IO;
654   }
655 
656   if (rv) {
657     switch (rv) {
658     case WSAEWOULDBLOCK:
659       return GWEN_ERROR_TIMEOUT;
660     case WSAEINTR:
661       return GWEN_ERROR_INTERRUPTED;
662     default:
663       DBG_INFO(GWEN_LOGDOMAIN, "getsockopt(): %d (%s)", rv, GWEN_ErrorString_Windows(rv));
664       return GWEN_ERROR_IO;
665     }
666   }
667 
668   return 0;
669 }
670 
671 
672 
GWEN_Socket_WaitForRead(GWEN_SOCKET * sp,int timeout)673 int GWEN_Socket_WaitForRead(GWEN_SOCKET *sp, int timeout)
674 {
675   int err;
676   GWEN_SOCKETSET *set;
677 
678   set=GWEN_SocketSet_new();
679 
680   err=GWEN_SocketSet_AddSocket(set, sp);
681   if (err) {
682     GWEN_SocketSet_free(set);
683     return err;
684   }
685   err=GWEN_Socket_Select(set, 0, 0, timeout);
686   GWEN_SocketSet_free(set);
687 
688   return err;
689 }
690 
691 
692 
GWEN_Socket_WaitForWrite(GWEN_SOCKET * sp,int timeout)693 int GWEN_Socket_WaitForWrite(GWEN_SOCKET *sp, int timeout)
694 {
695   int err;
696   GWEN_SOCKETSET *set;
697 
698   set=GWEN_SocketSet_new();
699   err=GWEN_SocketSet_AddSocket(set, sp);
700   if (err) {
701     GWEN_SocketSet_free(set);
702     return err;
703   }
704   err=GWEN_Socket_Select(0, set, 0, timeout);
705   GWEN_SocketSet_free(set);
706 
707   return err;
708 }
709 
710 
711 
GWEN_Socket_GetSocketType(GWEN_SOCKET * sp)712 GWEN_SOCKETTYPE GWEN_Socket_GetSocketType(GWEN_SOCKET *sp)
713 {
714   assert(sp);
715   return sp->type;
716 }
717 
718 
719 
GWEN_Socket_GetSocketInt(const GWEN_SOCKET * sp)720 int GWEN_Socket_GetSocketInt(const GWEN_SOCKET *sp)
721 {
722   assert(sp);
723   return sp->socket;
724 }
725 
726 
727 
GWEN_Socket_ErrorString(int c)728 const char *GWEN_Socket_ErrorString(int c)
729 {
730   const char *s;
731 
732   switch (c) {
733   case 0:
734     s="Success";
735     break;
736   case GWEN_SOCKET_ERROR_BAD_SOCKETTYPE:
737     s="Bad socket type";
738     break;
739   case GWEN_SOCKET_ERROR_NOT_OPEN:
740     s="Socket not open";
741     break;
742   case GWEN_SOCKET_ERROR_TIMEOUT:
743     s="Socket timeout";
744     break;
745   case GWEN_SOCKET_ERROR_IN_PROGRESS:
746     s="Operation in progress";
747     break;
748   case GWEN_SOCKET_ERROR_INTERRUPTED:
749     s="Operation interrupted by system signal.";
750     break;
751   case GWEN_SOCKET_ERROR_ABORTED:
752     s="Operation aborted by user.";
753     break;
754   case GWEN_SOCKET_ERROR_BROKEN_PIPE:
755     s="Broken connection.";
756     break;
757   default:
758     if (c>0)
759       s=GWEN_ErrorString_Windows(c);
760     else
761       s=(const char *)0;
762   } /* switch */
763   return s;
764 }
765 
766 
767 
768