Removed some includes of 16 bit API.
[wine] / misc / winsock.c
1 /*
2  * based on Windows Sockets 1.1 specs
3  * (ftp.microsoft.com:/Advsys/winsock/spec11/WINSOCK.TXT)
4  * 
5  * (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
6  *
7  * NOTE: If you make any changes to fix a particular app, make sure 
8  * they don't break something else like Netscape or telnet and ftp 
9  * clients and servers (www.winsite.com got a lot of those).
10  *
11  */
12  
13 #include "config.h"
14
15 #include <string.h>
16 #include <sys/types.h>
17 #include <sys/ipc.h>
18 #include <sys/ioctl.h>
19 #ifdef HAVE_SYS_FILIO_H
20 # include <sys/filio.h>
21 #endif
22 #if defined(__svr4__)
23 #include <sys/ioccom.h>
24 #include <sys/sockio.h>
25 #endif
26
27 #if defined(__EMX__)
28 # include <sys/so_ioctl.h>
29 #endif
30
31 #ifdef HAVE_SYS_PARAM_H
32 # include <sys/param.h>
33 #endif
34
35 #include <sys/msg.h>
36 #include <sys/wait.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <ctype.h>
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <sys/errno.h>
44 #include <netdb.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #ifdef HAVE_ARPA_NAMESER_H
48 # include <arpa/nameser.h>
49 #endif
50 #ifdef HAVE_RESOLV_H
51 # include <resolv.h>
52 #endif
53
54 #include "wine/winbase16.h"
55 #include "winsock.h"
56 #include "winnt.h"
57 #include "heap.h"
58 #include "task.h"
59 #include "message.h"
60 #include "miscemu.h"
61 #include "debug.h"
62
63 DEFAULT_DEBUG_CHANNEL(winsock)
64
65 #define DEBUG_SOCKADDR 0
66 #define dump_sockaddr(a) \
67         DUMP("sockaddr_in: family %d, address %s, port %d\n", \
68                         ((struct sockaddr_in *)a)->sin_family, \
69                         inet_ntoa(((struct sockaddr_in *)a)->sin_addr), \
70                         ntohs(((struct sockaddr_in *)a)->sin_port))
71
72 #pragma pack(4)
73
74 /* ----------------------------------- internal data */
75
76 static HANDLE   _WSHeap = 0;
77 static unsigned char*   _ws_stub = NULL;
78 static LPWSINFO         _wsi_list = NULL;
79
80 #define WS_ALLOC(size) \
81         HeapAlloc(_WSHeap, HEAP_ZERO_MEMORY, (size) )
82 #define WS_FREE(ptr) \
83         HeapFree(_WSHeap, 0, (ptr) )
84
85 #define WS_PTR2HANDLE(ptr) \
86         ((short)((int)(ptr) - (int)_ws_stub))
87 #define WS_HANDLE2PTR(handle) \
88         ((unsigned)((int)_ws_stub + (int)(handle)))
89
90 #define WSI_CHECK_RANGE(pwsi, pws) \
91         ( ((unsigned)(pws) > (unsigned)(pwsi)) && \
92           ((unsigned)(pws) < ((unsigned)(pwsi) + sizeof(WSINFO))) )
93
94 static INT         _ws_sock_ops[] =
95        { WS_SO_DEBUG, WS_SO_REUSEADDR, WS_SO_KEEPALIVE, WS_SO_DONTROUTE,
96          WS_SO_BROADCAST, WS_SO_LINGER, WS_SO_OOBINLINE, WS_SO_SNDBUF,
97          WS_SO_RCVBUF, WS_SO_ERROR, WS_SO_TYPE, WS_SO_DONTLINGER,
98 #ifdef SO_RCVTIMEO
99          WS_SO_RCVTIMEO,
100 #endif
101          0 };
102 static int           _px_sock_ops[] =
103        { SO_DEBUG, SO_REUSEADDR, SO_KEEPALIVE, SO_DONTROUTE, SO_BROADCAST,
104          SO_LINGER, SO_OOBINLINE, SO_SNDBUF, SO_RCVBUF, SO_ERROR, SO_TYPE,
105          SO_LINGER,
106 #ifdef SO_RCVTIMEO
107          SO_RCVTIMEO,
108 #endif
109         };
110
111 static INT _ws_tcp_ops[] = {
112 #ifdef TCP_NODELAY
113         WS_TCP_NODELAY,
114 #endif
115         0
116 };
117 static int _px_tcp_ops[] = {
118 #ifdef TCP_NODELAY
119         TCP_NODELAY,
120 #endif
121         0
122 };
123
124 static int   _check_ws(LPWSINFO pwsi, ws_socket* pws);
125 static char* _check_buffer(LPWSINFO pwsi, int size);
126
127 /* ----------------------------------- non-blocking I/O */
128
129 static int WINSOCK_unblock_io(int fd, int noblock)
130 {
131     int fd_flags;
132
133     fd_flags = fcntl(fd, F_GETFL, 0);
134     if (fcntl(fd, F_SETFL, (noblock)? fd_flags |  O_NONBLOCK
135                                     : fd_flags & ~O_NONBLOCK ) != -1) return 0;
136     return -1;
137 }
138
139 /***********************************************************************
140  *          convert_sockopt()
141  *
142  * Converts socket flags from Windows format.
143  */
144 static void convert_sockopt(INT *level, INT *optname)
145 {
146   int i;
147   switch (*level)
148   {
149      case WS_SOL_SOCKET:
150         *level = SOL_SOCKET;
151         for(i=0; _ws_sock_ops[i]; i++)
152             if( _ws_sock_ops[i] == *optname ) break;
153         if( _ws_sock_ops[i] ) *optname = _px_sock_ops[i];
154         else FIXME(winsock, "Unknown SOL_SOCKET optname %d\n", *optname);
155         break;
156      case WS_IPPROTO_TCP:
157         *level = IPPROTO_TCP;
158         for(i=0; _ws_tcp_ops[i]; i++)
159                 if ( _ws_tcp_ops[i] == *optname ) break;
160         if( _ws_tcp_ops[i] ) *optname = _px_tcp_ops[i];
161         else FIXME(winsock, "Unknown IPPROTO_TCP optname %d\n", *optname);
162         break;
163   }
164 }
165
166 /* ----------------------------------- Per-thread info (or per-process?) */
167
168 static LPWSINFO wsi_find(HTASK16 hTask)
169
170     TDB*           pTask = (TDB*)GlobalLock16(hTask);
171     if( pTask )
172     {
173         if( pTask->pwsi ) return pTask->pwsi;
174         else
175         {
176             LPWSINFO pwsi = _wsi_list;
177             while( pwsi && pwsi->tid != hTask ) pwsi = pwsi->next;
178             if( pwsi )
179                 WARN(winsock,"(pwsi=0x%08x,task=0x%04x):Loose wsi struct! \n", 
180                                         (unsigned)pwsi, hTask );
181             return pwsi; 
182         }
183     }
184     return NULL;
185 }
186
187 static ws_socket* wsi_alloc_socket(LPWSINFO pwsi, int fd)
188 {
189     /* Initialize a new entry in the socket table */
190
191     if( pwsi->last_free >= 0 )
192     {
193         int i = pwsi->last_free;
194
195         pwsi->last_free = pwsi->sock[i].flags;  /* free list */
196         pwsi->sock[i].fd = fd;
197         pwsi->sock[i].flags = 0;
198         return &pwsi->sock[i];
199     }
200     return NULL;
201 }
202
203 static int wsi_strtolo(LPWSINFO pwsi, const char* name, const char* opt)
204 {
205     /* Stuff a lowercase copy of the string into the local buffer */
206
207     int i = strlen(name) + 2;
208     char* p = _check_buffer(pwsi, i + ((opt)?strlen(opt):0));
209
210     if( p )
211     {
212         do *p++ = tolower(*name); while(*name++);
213         i = (p - (char*)(pwsi->buffer));
214         if( opt ) do *p++ = tolower(*opt); while(*opt++);
215         return i;
216     }
217     return 0;
218 }
219
220 static fd_set* fd_set_import( fd_set* fds, LPWSINFO pwsi, void* wsfds, int* highfd, BOOL b32 )
221 {
222     /* translate Winsock fd set into local fd set */
223
224     if( wsfds ) 
225     { 
226 #define wsfds16 ((ws_fd_set16*)wsfds)
227 #define wsfds32 ((ws_fd_set32*)wsfds)
228         ws_socket* pws;
229         int i, count;
230
231         FD_ZERO(fds);
232         count = b32 ? wsfds32->fd_count : wsfds16->fd_count;
233
234         for( i = 0; i < count; i++ )
235         {
236              pws = (b32) ? (ws_socket*)WS_HANDLE2PTR(wsfds32->fd_array[i])
237                          : (ws_socket*)WS_HANDLE2PTR(wsfds16->fd_array[i]);
238              if( _check_ws(pwsi, pws) )
239              {
240                     if( pws->fd > *highfd ) *highfd = pws->fd;
241                     FD_SET(pws->fd, fds);
242              }
243         }
244 #undef wsfds32
245 #undef wsfds16
246         return fds;
247     }
248     return NULL;
249 }
250
251 __inline__ static int sock_error_p(int s)
252 {
253     unsigned int optval, optlen;
254
255     optlen = sizeof(optval);
256     getsockopt(s, SOL_SOCKET, SO_ERROR, &optval, &optlen);
257     if (optval) WARN(winsock, "\t[%i] error: %d\n", s, optval);
258     return optval != 0;
259 }
260
261 static int fd_set_export( LPWSINFO pwsi, fd_set* fds, fd_set* exceptfds, void* wsfds, BOOL b32 )
262 {
263     int num_err = 0;
264
265     /* translate local fd set into Winsock fd set, adding
266      * errors to exceptfds (only if app requested it) */
267
268     if( wsfds )
269     {
270 #define wsfds16 ((ws_fd_set16*)wsfds)
271 #define wsfds32 ((ws_fd_set32*)wsfds)
272         int i, j, count = (b32) ? wsfds32->fd_count : wsfds16->fd_count;
273
274         for( i = 0, j = 0; i < count; i++ )
275         {
276             ws_socket *pws = (b32) ? (ws_socket*)WS_HANDLE2PTR(wsfds32->fd_array[i])
277                                    : (ws_socket*)WS_HANDLE2PTR(wsfds16->fd_array[i]);
278             if( _check_ws(pwsi, pws) )
279             {
280                 int fd = pws->fd;
281
282                 if( FD_ISSET(fd, fds) )
283                 {
284                     if ( exceptfds && sock_error_p(fd) )
285                     {
286                         FD_SET(fd, exceptfds);
287                         num_err++;
288                     }
289                     else if( b32 )
290                              wsfds32->fd_array[j++] = wsfds32->fd_array[i];
291                          else
292                              wsfds16->fd_array[j++] = wsfds16->fd_array[i];
293                 }
294             }
295         }
296
297         if( b32 ) wsfds32->fd_count = j;
298         else wsfds16->fd_count = j;
299
300         TRACE(winsock, "\n");
301 #undef wsfds32
302 #undef wsfds16
303     }
304     return num_err;
305 }
306
307 HANDLE16 __ws_gethandle( void* ptr )
308 {
309     return (HANDLE16)WS_PTR2HANDLE(ptr);
310 }
311
312 void* __ws_memalloc( int size )
313 {
314     return WS_ALLOC(size);
315 }
316
317 void __ws_memfree(void* ptr)
318 {
319     WS_FREE(ptr);
320 }
321
322 /* ----------------------------------- API ----- 
323  *
324  * Init / cleanup / error checking.
325  */
326
327 /***********************************************************************
328  *      WSAStartup16()                  (WINSOCK.115)
329  *
330  * Create socket control struct, attach it to the global list and
331  * update a pointer in the task struct.
332  */
333 INT16 WINAPI WSAStartup16(UINT16 wVersionRequested, LPWSADATA lpWSAData)
334 {
335     WSADATA WINSOCK_data = { 0x0101, 0x0101,
336                           "WINE Sockets 1.1",
337                         #ifdef linux
338                                 "Linux/i386",
339                         #elif defined(__NetBSD__)
340                                 "NetBSD/i386",
341                         #elif defined(sunos)
342                                 "SunOS",
343                         #elif defined(__FreeBSD__)
344                                 "FreeBSD",
345                         #elif defined(__OpenBSD__)
346                                 "OpenBSD/i386",
347                         #else
348                                 "Unknown",
349                         #endif
350                            WS_MAX_SOCKETS_PER_PROCESS,
351                            WS_MAX_UDP_DATAGRAM, (SEGPTR)NULL };
352     HTASK16             tid = GetCurrentTask();
353     LPWSINFO            pwsi;
354
355     TRACE(winsock, "verReq=%x\n", wVersionRequested);
356
357     if (LOBYTE(wVersionRequested) < 1 || (LOBYTE(wVersionRequested) == 1 &&
358         HIBYTE(wVersionRequested) < 1)) return WSAVERNOTSUPPORTED;
359
360     if (!lpWSAData) return WSAEINVAL;
361
362     /* initialize socket heap */
363
364     if( !_ws_stub )
365     {
366         _WSHeap = HeapCreate(HEAP_ZERO_MEMORY, 8120, 32768);
367         if( !(_ws_stub = WS_ALLOC(0x10)) )
368         {
369             ERR(winsock,"Fatal: failed to create WinSock heap\n");
370             return 0;
371         }
372     }
373     if( _WSHeap == 0 ) return WSASYSNOTREADY;
374
375     /* create socket array for this task */
376   
377     pwsi = wsi_find(GetCurrentTask());
378     if( pwsi == NULL )
379     {
380         TDB* pTask = (TDB*)GlobalLock16( tid );
381
382         if( (pwsi = (LPWSINFO)WS_ALLOC( sizeof(WSINFO))) )
383         {
384             int i = 0;
385             pwsi->tid = tid;
386             for( i = 0; i < WS_MAX_SOCKETS_PER_PROCESS; i++ )
387             {
388                 pwsi->sock[i].fd = -1; 
389                 pwsi->sock[i].flags = i + 1; 
390             }
391             pwsi->sock[WS_MAX_SOCKETS_PER_PROCESS - 1].flags = -1;
392         }
393         else return WSASYSNOTREADY;
394
395         /* add this control struct to the global list */
396
397         pwsi->prev = NULL;
398         if( _wsi_list ) 
399             _wsi_list->prev = pwsi;
400         pwsi->next = _wsi_list; 
401         _wsi_list = pwsi;
402         pTask->pwsi = pwsi;
403     }
404     else pwsi->num_startup++;
405
406     /* return winsock information */
407
408     memcpy(lpWSAData, &WINSOCK_data, sizeof(WINSOCK_data));
409
410     TRACE(winsock, "succeeded\n");
411     return 0;
412 }
413
414 /***********************************************************************
415  *      WSAStartup32()                  (WSOCK32.115)
416  */
417 INT WINAPI WSAStartup(UINT wVersionRequested, LPWSADATA lpWSAData)
418 {
419     return WSAStartup16( wVersionRequested, lpWSAData );
420 }
421
422 /***********************************************************************
423  *      WSACleanup()                    (WINSOCK.116)
424  *
425  * Cleanup functions of varying impact.
426  */
427 void WINSOCK_Shutdown()
428 {
429     /* Called on exit(), has to remove all outstanding async DNS processes.  */
430 }
431
432 INT WINSOCK_DeleteTaskWSI( TDB* pTask, LPWSINFO pwsi )
433 {
434     /* WSACleanup() backend, called on task termination as well.
435      * Real DLL would have registered its own signal handler with
436      * TaskSetSignalHandler() and waited until USIG_TERMINATION/USIG_GPF
437      * but this scheme is much more straightforward.
438      */
439
440     int i, j, n;
441
442     if( --pwsi->num_startup > 0 ) return 0;
443
444     /* unlink socket control struct */
445
446     if( pwsi == _wsi_list ) 
447         _wsi_list = pwsi->next;
448     else
449         pwsi->prev->next = pwsi->next;
450     if( pwsi->next ) pwsi->next->prev = pwsi->prev; 
451
452     if( _wsi_list == NULL ) 
453         WINSOCK_Shutdown();     /* just in case */
454
455     if( pwsi->flags & WSI_BLOCKINGCALL )
456         TRACE(winsock,"\tinside blocking call!\n");
457
458 /* FIXME: aop_control() doesn't decrement pwsi->num_async_rq
459  *
460  *    if( pwsi->num_async_rq )
461  *        WARN(winsock,"\thave %i outstanding async ops!\n", pwsi->num_async_rq );
462  */
463
464     for(i = 0, j = 0, n = 0; i < WS_MAX_SOCKETS_PER_PROCESS; i++)
465         if( pwsi->sock[i].fd != -1 )
466         {
467             if( pwsi->sock[i].psop )
468             {
469                 n++;
470                 WSAAsyncSelect( (SOCKET16)WS_PTR2HANDLE(pwsi->sock + i), 0, 0, 0 );
471             }
472             close(pwsi->sock[i].fd); j++; 
473         }
474     if( j ) 
475           TRACE(winsock,"\tclosed %i sockets, killed %i async selects!\n", j, n);
476
477     /* delete scratch buffers */
478
479     if( pwsi->buffer ) SEGPTR_FREE(pwsi->buffer);
480     if( pwsi->dbuffer ) SEGPTR_FREE(pwsi->dbuffer);
481         
482     if( pTask )
483         pTask->pwsi = NULL;
484     memset( pwsi, 0, sizeof(WSINFO) );
485     WS_FREE(pwsi);
486     return 0;
487 }
488
489 INT WINAPI WSACleanup(void)
490 {
491     HTASK16     hTask = GetCurrentTask();
492
493     TRACE(winsock, "(%04x)\n", hTask );
494     if( hTask )
495     {
496         LPWSINFO pwsi = wsi_find(hTask);
497         if( pwsi )
498             return WINSOCK_DeleteTaskWSI( (TDB*)GlobalLock16(hTask), pwsi );
499         return SOCKET_ERROR;
500     }
501     else
502         WINSOCK_Shutdown(); /* remove all outstanding DNS requests */
503     return 0;
504 }
505
506
507 /***********************************************************************
508  *      WSAGetLastError()               (WSOCK32.111)(WINSOCK.111)
509  */
510 INT WINAPI WSAGetLastError(void)
511 {
512     LPWSINFO pwsi = wsi_find(GetCurrentTask());
513     INT16    ret = (pwsi) ? pwsi->err : WSANOTINITIALISED;
514
515     TRACE(winsock, "(%08x) = %i\n", 
516                     (unsigned)pwsi, (int)ret);
517     return ret;
518 }
519
520 /***********************************************************************
521  *      WSASetLastError32()             (WSOCK32.112)
522  */
523 void WINAPI WSASetLastError(INT iError)
524 {
525     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
526
527     TRACE(winsock, "(%08x): %d\n", (unsigned)pwsi, (int)iError);
528     if( pwsi ) pwsi->err = iError;
529 }
530
531 /***********************************************************************
532  *      WSASetLastError16()             (WINSOCK.112)
533  */
534 void WINAPI WSASetLastError16(INT16 iError)
535 {
536     WSASetLastError(iError);
537 }
538
539 int _check_ws(LPWSINFO pwsi, ws_socket* pws)
540 {
541     if( pwsi )
542     {
543         if( pwsi->flags & WSI_BLOCKINGCALL ) pwsi->err = WSAEINPROGRESS;
544         else if( WSI_CHECK_RANGE(pwsi, pws) ) return 1;
545                  else pwsi->err = WSAENOTSOCK;
546     }
547     return 0;
548 }
549
550 char* _check_buffer(LPWSINFO pwsi, int size)
551 {
552     if( pwsi->buffer && pwsi->buflen >= size ) return pwsi->buffer;
553     else SEGPTR_FREE(pwsi->buffer);
554
555     pwsi->buffer = (char*)SEGPTR_ALLOC((pwsi->buflen = size)); 
556     return pwsi->buffer;
557 }
558
559 struct ws_hostent* _check_buffer_he(LPWSINFO pwsi, int size)
560 {
561     if( pwsi->he && pwsi->helen >= size ) return pwsi->he;
562     else SEGPTR_FREE(pwsi->he);
563
564     pwsi->he = (struct ws_hostent*)SEGPTR_ALLOC((pwsi->helen = size)); 
565     return pwsi->he;
566 }
567
568 struct ws_servent* _check_buffer_se(LPWSINFO pwsi, int size)
569 {
570     if( pwsi->se && pwsi->selen >= size ) return pwsi->se;
571     else SEGPTR_FREE(pwsi->se);
572
573     pwsi->se = (struct ws_servent*)SEGPTR_ALLOC((pwsi->selen = size)); 
574     return pwsi->se;
575 }
576
577 struct ws_protoent* _check_buffer_pe(LPWSINFO pwsi, int size)
578 {
579     if( pwsi->pe && pwsi->pelen >= size ) return pwsi->pe;
580     else SEGPTR_FREE(pwsi->pe);
581
582     pwsi->pe = (struct ws_protoent*)SEGPTR_ALLOC((pwsi->pelen = size)); 
583     return pwsi->pe;
584 }
585
586 /* ----------------------------------- i/o APIs */
587
588 /***********************************************************************
589  *              accept()                (WSOCK32.1)
590  */
591 SOCKET WINAPI WINSOCK_accept(SOCKET s, struct sockaddr *addr,
592                                  INT *addrlen32)
593 {
594     ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR((SOCKET16)s);
595     LPWSINFO                 pwsi = wsi_find(GetCurrentTask());
596 #ifdef HAVE_IPX
597     struct ws_sockaddr_ipx*  addr2 = (struct ws_sockaddr_ipx *)addr;
598 #endif
599
600     TRACE(winsock, "(%08x): socket %04x\n", 
601                                   (unsigned)pwsi, (UINT16)s ); 
602     if( _check_ws(pwsi, pws) )
603     {
604         int     sock, fd_flags;
605
606         fd_flags = fcntl(pws->fd, F_GETFL, 0);
607
608         if( (sock = accept(pws->fd, addr, addrlen32)) >= 0 )
609         {
610             ws_socket*  pnew = wsi_alloc_socket(pwsi, sock); 
611             if( pnew )
612             {
613                 s = (SOCKET)WS_PTR2HANDLE(pnew);
614                 if( pws->psop && pws->flags & WS_FD_ACCEPT )
615                 {
616                     EVENT_AddIO( pws->fd, EVENT_IO_READ );      /* reenabler */
617
618                     /* async select the accept()'ed socket */
619                     WSAAsyncSelect( s, pws->psop->hWnd, pws->psop->uMsg,
620                                       pws->flags & ~WS_FD_ACCEPT );
621                 }
622 #ifdef HAVE_IPX
623                 if (addr && ((struct sockaddr_ipx *)addr)->sipx_family == AF_IPX) {
624                     addr = (struct sockaddr *)
625                                 malloc(addrlen32 ? *addrlen32 : sizeof(*addr2));
626                     memcpy(addr, addr2,
627                                 addrlen32 ? *addrlen32 : sizeof(*addr2));
628                     addr2->sipx_family = WS_AF_IPX;
629                     addr2->sipx_network = ((struct sockaddr_ipx *)addr)->sipx_network;
630                     addr2->sipx_port = ((struct sockaddr_ipx *)addr)->sipx_port;
631                     memcpy(addr2->sipx_node,
632                         ((struct sockaddr_ipx *)addr)->sipx_node, IPX_NODE_LEN);
633                     free(addr);
634                 }
635 #endif
636                 return s;
637             } 
638             else pwsi->err = WSAENOBUFS;
639         } 
640         else pwsi->err = wsaErrno();
641     }
642 #ifdef HAVE_IPX
643     if (addr && ((struct sockaddr_ipx *)addr)->sipx_family == AF_IPX) {
644         addr = (struct sockaddr *)
645                         malloc(addrlen32 ? *addrlen32 : sizeof(*addr2));
646         memcpy(addr, addr2, addrlen32 ? *addrlen32 : sizeof(*addr2));
647         addr2->sipx_family = WS_AF_IPX;
648         addr2->sipx_network = ((struct sockaddr_ipx *)addr)->sipx_network;
649         addr2->sipx_port = ((struct sockaddr_ipx *)addr)->sipx_port;
650         memcpy(addr2->sipx_node,
651             ((struct sockaddr_ipx *)addr)->sipx_node, IPX_NODE_LEN);
652         free(addr);
653     }
654 #endif
655     return INVALID_SOCKET;
656 }
657
658 /***********************************************************************
659  *              accept()                (WINSOCK.1)
660  */
661 SOCKET16 WINAPI WINSOCK_accept16(SOCKET16 s, struct sockaddr* addr,
662                                  INT16* addrlen16 )
663 {
664     INT addrlen32 = addrlen16 ? *addrlen16 : 0;
665     SOCKET retSocket = WINSOCK_accept( s, addr, &addrlen32 );
666     if( addrlen16 ) *addrlen16 = (INT16)addrlen32;
667     return (SOCKET16)retSocket;
668 }
669
670 /***********************************************************************
671  *              bind()                  (WSOCK32.2)
672  */
673 INT WINAPI WINSOCK_bind(SOCKET s, struct sockaddr *name, INT namelen)
674 {
675     ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s);
676     LPWSINFO                 pwsi = wsi_find(GetCurrentTask());
677 #ifdef HAVE_IPX
678     struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name;
679 #endif
680
681     TRACE(winsock, "(%08x): socket %04x, ptr %8x, length %d\n", 
682                            (unsigned)pwsi, s, (int) name, namelen);
683 #if DEBUG_SOCKADDR
684     dump_sockaddr(name);
685 #endif
686
687     if ( _check_ws(pwsi, pws) )
688     {
689       /* FIXME: what family does this really map to on the Unix side? */
690       if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_PUP)
691         ((struct ws_sockaddr_ipx *)name)->sipx_family = AF_UNSPEC;
692 #ifdef HAVE_IPX
693       else if (name &&
694                 ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_IPX)
695       {
696         name = (struct sockaddr *) malloc(sizeof(struct sockaddr_ipx));
697         memset(name, '\0', sizeof(struct sockaddr_ipx));
698         ((struct sockaddr_ipx *)name)->sipx_family = AF_IPX;
699         ((struct sockaddr_ipx *)name)->sipx_port = name2->sipx_port;
700         ((struct sockaddr_ipx *)name)->sipx_network = name2->sipx_network;
701         memcpy(((struct sockaddr_ipx *)name)->sipx_node,
702                 name2->sipx_node, IPX_NODE_LEN);
703         namelen = sizeof(struct sockaddr_ipx);
704       }
705 #endif
706       if ( namelen >= sizeof(*name) ) 
707       {
708         if ( name && (((struct ws_sockaddr_in *)name)->sin_family == AF_INET
709 #ifdef HAVE_IPX
710              || ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX
711 #endif
712            ))
713         {
714           if ( bind(pws->fd, name, namelen) < 0 ) 
715           {
716              int        loc_errno = errno;
717              WARN(winsock, "\tfailure - errno = %i\n", errno);
718              errno = loc_errno;
719              switch(errno)
720              {
721                 case EBADF: pwsi->err = WSAENOTSOCK; break;
722                 case EADDRNOTAVAIL: pwsi->err = WSAEINVAL; break;
723                 default: pwsi->err = wsaErrno();
724              }
725           }
726           else {
727 #ifdef HAVE_IPX
728             if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
729                 free(name);
730 #endif
731             return 0; /* success */
732           }
733         }
734         else pwsi->err = WSAEAFNOSUPPORT;
735       }
736       else pwsi->err = WSAEFAULT;
737 #ifdef HAVE_IPX
738       if (name && ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
739         free(name);
740 #endif
741     }
742     return SOCKET_ERROR;
743 }
744
745 /***********************************************************************
746  *              bind()                  (WINSOCK.2)
747  */
748 INT16 WINAPI WINSOCK_bind16(SOCKET16 s, struct sockaddr *name, INT16 namelen)
749 {
750   return (INT16)WINSOCK_bind( s, name, namelen );
751 }
752
753 /***********************************************************************
754  *              closesocket()           (WSOCK32.3)
755  */
756 INT WINAPI WINSOCK_closesocket(SOCKET s)
757 {
758     ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s);
759     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
760
761     TRACE(winsock, "(%08x): socket %08x\n", (unsigned)pwsi, s);
762
763     if( _check_ws(pwsi, pws) )
764     { 
765         int     fd = pws->fd;
766
767         if( pws->psop ) WSAAsyncSelect( s, 0, 0, 0 );
768
769         pws->fd = -1;
770         pws->flags = (unsigned)pwsi->last_free;
771         pwsi->last_free = pws - &pwsi->sock[0]; /* add to free list */
772
773         if( close(fd) == 0 ) 
774             return 0;
775         pwsi->err = (errno == EBADF) ? WSAENOTSOCK : wsaErrno();
776     }
777     return SOCKET_ERROR;
778 }
779
780 /***********************************************************************
781  *              closesocket()           (WINSOCK.3)
782  */
783 INT16 WINAPI WINSOCK_closesocket16(SOCKET16 s)
784 {
785     return (INT16)WINSOCK_closesocket(s);
786 }
787
788 /***********************************************************************
789  *              connect()               (WSOCK32.4)
790  */
791 INT WINAPI WINSOCK_connect(SOCKET s, struct sockaddr *name, INT namelen)
792 {
793   ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s);
794   LPWSINFO                 pwsi = wsi_find(GetCurrentTask());
795 #ifdef HAVE_IPX
796   struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name;
797 #endif
798
799   TRACE(winsock, "(%08x): socket %04x, ptr %8x, length %d\n", 
800                            (unsigned)pwsi, s, (int) name, namelen);
801 #if DEBUG_SOCKADDR
802   dump_sockaddr(name);
803 #endif
804
805   if( _check_ws(pwsi, pws) )
806   {
807     if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_PUP)
808         ((struct ws_sockaddr_ipx *)name)->sipx_family = AF_UNSPEC;
809 #ifdef HAVE_IPX
810     else if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_IPX)
811     {
812         name = (struct sockaddr *) malloc(sizeof(struct sockaddr_ipx));
813         memset(name, '\0', sizeof(struct sockaddr_ipx));
814         ((struct sockaddr_ipx *)name)->sipx_family = AF_IPX;
815         ((struct sockaddr_ipx *)name)->sipx_port = name2->sipx_port;
816         ((struct sockaddr_ipx *)name)->sipx_network = name2->sipx_network;
817         memcpy(((struct sockaddr_ipx *)name)->sipx_node,
818                 name2->sipx_node, IPX_NODE_LEN);
819         namelen = sizeof(struct sockaddr_ipx);
820     }
821 #endif
822     if (connect(pws->fd, name, namelen) == 0) 
823     { 
824         if( pws->psop && (pws->flags & WS_FD_CONNECT) )
825         {
826             /* application did AsyncSelect() but then went
827              * ahead and called connect() without waiting for 
828              * notification.
829              *
830              * FIXME: Do we have to post a notification message 
831              *        in this case?
832              */
833
834             if( !(pws->flags & WS_FD_CONNECTED) )
835             {
836                 if( pws->flags & (WS_FD_READ | WS_FD_CLOSE) )
837                     EVENT_AddIO( pws->fd, EVENT_IO_READ );
838                 else
839                     EVENT_DeleteIO( pws->fd, EVENT_IO_READ );
840                 if( pws->flags & WS_FD_WRITE )
841                     EVENT_AddIO( pws->fd, EVENT_IO_WRITE );
842                 else
843                     EVENT_DeleteIO( pws->fd, EVENT_IO_WRITE );
844             }
845         }
846         pws->flags |= WS_FD_CONNECTED;
847         pws->flags &= ~(WS_FD_INACTIVE | WS_FD_CONNECT | WS_FD_LISTENING);
848 #ifdef HAVE_IPX
849         if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
850             free(name);
851 #endif
852         return 0; 
853     }
854     pwsi->err = (errno == EINPROGRESS) ? WSAEWOULDBLOCK : wsaErrno();
855   }
856 #ifdef HAVE_IPX
857   if (name && ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
858     free(name);
859 #endif
860   return SOCKET_ERROR;
861 }
862
863 /***********************************************************************
864  *              connect()               (WINSOCK.4)
865  */
866 INT16 WINAPI WINSOCK_connect16(SOCKET16 s, struct sockaddr *name, INT16 namelen)
867 {
868   return (INT16)WINSOCK_connect( s, name, namelen );
869 }
870
871 /***********************************************************************
872  *              getpeername()           (WSOCK32.5)
873  */
874 INT WINAPI WINSOCK_getpeername(SOCKET s, struct sockaddr *name,
875                                    INT *namelen)
876 {
877     ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s);
878     LPWSINFO                 pwsi = wsi_find(GetCurrentTask());
879 #ifdef HAVE_IPX
880     struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name;
881 #endif
882
883     TRACE(winsock, "(%08x): socket: %04x, ptr %8x, ptr %8x\n", 
884                            (unsigned)pwsi, s, (int) name, *namelen);
885     if( _check_ws(pwsi, pws) )
886     {
887         if (getpeername(pws->fd, name, namelen) == 0) {
888 #ifdef HAVE_IPX
889             if (((struct ws_sockaddr_ipx *)name)->sipx_family == AF_IPX) {
890                 name = (struct sockaddr *)
891                                 malloc(namelen ? *namelen : sizeof(*name2));
892                 memcpy(name, name2, namelen ? *namelen : sizeof(*name2));
893                 name2->sipx_family = WS_AF_IPX;
894                 name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network;
895                 name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port;
896                 memcpy(name2->sipx_node,
897                         ((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN);
898                 free(name);
899             }
900 #endif
901             return 0; 
902         }
903         pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
904     }
905 #ifdef HAVE_IPX
906     if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == AF_IPX) {
907         name = (struct sockaddr *) malloc(namelen ? *namelen : sizeof(*name2));
908         memcpy(name, name2, namelen ? *namelen : sizeof(*name2));
909         name2->sipx_family = WS_AF_IPX;
910         name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network;
911         name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port;
912         memcpy(name2->sipx_node,
913                 ((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN);
914         free(name);
915     }
916 #endif
917     return SOCKET_ERROR;
918 }
919
920 /***********************************************************************
921  *              getpeername()           (WINSOCK.5)
922  */
923 INT16 WINAPI WINSOCK_getpeername16(SOCKET16 s, struct sockaddr *name,
924                                    INT16 *namelen16)
925 {
926     INT namelen32 = *namelen16;
927     INT retVal = WINSOCK_getpeername( s, name, &namelen32 );
928
929 #if DEBUG_SOCKADDR
930     dump_sockaddr(name);
931 #endif
932
933    *namelen16 = namelen32;
934     return (INT16)retVal;
935 }
936
937 /***********************************************************************
938  *              getsockname()           (WSOCK32.6)
939  */
940 INT WINAPI WINSOCK_getsockname(SOCKET s, struct sockaddr *name,
941                                    INT *namelen)
942 {
943     ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s);
944     LPWSINFO                 pwsi = wsi_find(GetCurrentTask());
945 #ifdef HAVE_IPX
946     struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name;
947 #endif
948
949     TRACE(winsock, "(%08x): socket: %04x, ptr %8x, ptr %8x\n", 
950                           (unsigned)pwsi, s, (int) name, (int) *namelen);
951     if( _check_ws(pwsi, pws) )
952     {
953         if (getsockname(pws->fd, name, namelen) == 0) {
954 #ifdef HAVE_IPX
955             if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX) {
956                 name = (struct sockaddr *)
957                                 malloc(namelen ? *namelen : sizeof(*name2));
958                 memcpy(name, name2, namelen ? *namelen : sizeof(*name2));
959                 name2->sipx_family = WS_AF_IPX;
960                 name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network;
961                 name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port;
962                 memcpy(name2->sipx_node,
963                         ((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN);
964                 free(name);
965             }
966 #endif
967             return 0; 
968         }
969         pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
970     }
971 #ifdef HAVE_IPX
972     if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == AF_IPX) {
973         name = (struct sockaddr *) malloc(namelen ? *namelen : sizeof(*name2));
974         memcpy(name, name2, namelen ? *namelen : sizeof(*name2));
975         name2->sipx_family = WS_AF_IPX;
976         name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network;
977         name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port;
978         memcpy(name2->sipx_node,
979                 ((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN);
980         free(name);
981     }
982 #endif
983     return SOCKET_ERROR;
984 }
985
986 /***********************************************************************
987  *              getsockname()           (WINSOCK.6)
988  */
989 INT16 WINAPI WINSOCK_getsockname16(SOCKET16 s, struct sockaddr *name,
990                                    INT16 *namelen16)
991 {
992     INT retVal;
993
994     if( namelen16 )
995     {
996         INT namelen32 = *namelen16;
997         retVal = WINSOCK_getsockname( s, name, &namelen32 );
998        *namelen16 = namelen32;
999
1000 #if DEBUG_SOCKADDR
1001     dump_sockaddr(name);
1002 #endif
1003
1004     }
1005     else retVal = SOCKET_ERROR;
1006     return (INT16)retVal;
1007 }
1008
1009
1010 /***********************************************************************
1011  *              getsockopt()            (WSOCK32.7)
1012  */
1013 INT WINAPI WINSOCK_getsockopt(SOCKET s, INT level, 
1014                                   INT optname, char *optval, INT *optlen)
1015 {
1016     ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s);
1017     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
1018
1019     TRACE(winsock, "(%08x): socket: %04x, opt %d, ptr %8x, ptr %8x\n", 
1020                            (unsigned)pwsi, s, level, (int) optval, (int) *optlen);
1021     if( _check_ws(pwsi, pws) )
1022     {
1023         convert_sockopt(&level, &optname);
1024         if (getsockopt(pws->fd, (int) level, optname, optval, optlen) == 0 )
1025             return 0;
1026         pwsi->err = (errno == EBADF) ? WSAENOTSOCK : wsaErrno();
1027     }
1028     return SOCKET_ERROR;
1029 }
1030
1031 /***********************************************************************
1032  *              getsockopt()            (WINSOCK.7)
1033  */
1034 INT16 WINAPI WINSOCK_getsockopt16(SOCKET16 s, INT16 level,
1035                                   INT16 optname, char *optval, INT16 *optlen)
1036 {
1037     INT optlen32;
1038     INT *p = &optlen32;
1039     INT retVal;
1040     if( optlen ) optlen32 = *optlen; else p = NULL;
1041     retVal = WINSOCK_getsockopt( s, (UINT16)level, optname, optval, p );
1042     if( optlen ) *optlen = optlen32;
1043     return (INT16)retVal;
1044 }
1045
1046 /***********************************************************************
1047  *              htonl()                 (WINSOCK.8)(WSOCK32.8)
1048  */
1049 u_long WINAPI WINSOCK_htonl(u_long hostlong)   { return( htonl(hostlong) ); }
1050 /***********************************************************************
1051  *              htons()                 (WINSOCK.9)(WSOCK32.9)
1052  */
1053 u_short WINAPI WINSOCK_htons(u_short hostshort) { return( htons(hostshort) ); }
1054 /***********************************************************************
1055  *              inet_addr()             (WINSOCK.10)(WSOCK32.10)
1056  */
1057 u_long WINAPI WINSOCK_inet_addr(char *cp)      { return( inet_addr(cp) ); }
1058 /***********************************************************************
1059  *              htohl()                 (WINSOCK.14)(WSOCK32.14)
1060  */
1061 u_long WINAPI WINSOCK_ntohl(u_long netlong)    { return( ntohl(netlong) ); }
1062 /***********************************************************************
1063  *              ntohs()                 (WINSOCK.15)(WSOCK32.15)
1064  */
1065 u_short WINAPI WINSOCK_ntohs(u_short netshort)  { return( ntohs(netshort) ); }
1066
1067 /***********************************************************************
1068  *              inet_ntoa()             (WINSOCK.11)(WSOCK32.11)
1069  */
1070 char* WINAPI WINSOCK_inet_ntoa(struct in_addr in)
1071 {
1072   /* use "buffer for dummies" here because some applications have 
1073    * propensity to decode addresses in ws_hostent structure without 
1074    * saving them first...
1075    */
1076
1077     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
1078
1079     if( pwsi )
1080     {
1081         char*   s = inet_ntoa(in);
1082         if( s ) 
1083         {
1084             if( pwsi->dbuffer == NULL )
1085                 if((pwsi->dbuffer = (char*) SEGPTR_ALLOC(32)) == NULL )
1086                 {
1087                     pwsi->err = WSAENOBUFS;
1088                     return NULL;
1089                 }
1090             strncpy(pwsi->dbuffer, s, 32 );
1091             return pwsi->dbuffer; 
1092         }
1093         pwsi->err = wsaErrno();
1094     }
1095     return NULL;
1096 }
1097
1098 SEGPTR WINAPI WINSOCK_inet_ntoa16(struct in_addr in)
1099 {
1100   char* retVal = WINSOCK_inet_ntoa(in);
1101   return retVal ? SEGPTR_GET(retVal) : (SEGPTR)NULL;
1102 }
1103
1104 /***********************************************************************
1105  *              ioctlsocket()           (WSOCK32.12)
1106  */
1107 INT WINAPI WINSOCK_ioctlsocket(SOCKET s, UINT cmd, UINT *argp)
1108 {
1109   ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s);
1110   LPWSINFO      pwsi = wsi_find(GetCurrentTask());
1111
1112   TRACE(winsock, "(%08x): socket %04x, cmd %08x, ptr %8x\n", 
1113                           (unsigned)pwsi, s, cmd, (unsigned) argp);
1114   if( _check_ws(pwsi, pws) )
1115   {
1116     long        newcmd  = cmd;
1117
1118     switch( cmd )
1119     {
1120         case WS_FIONREAD:   
1121                 newcmd=FIONREAD; 
1122                 break;
1123
1124         case WS_FIONBIO:    
1125                 newcmd=FIONBIO;  
1126                 if( pws->psop && *argp == 0 ) 
1127                 {
1128                     /* AsyncSelect()'ed sockets are always nonblocking */
1129                     pwsi->err = WSAEINVAL; 
1130                     return SOCKET_ERROR; 
1131                 }
1132                 break;
1133
1134         case WS_SIOCATMARK: 
1135                 newcmd=SIOCATMARK; 
1136                 break;
1137
1138         case WS_IOW('f',125,u_long): 
1139                 WARN(winsock,"Warning: WS1.1 shouldn't be using async I/O\n");
1140                 pwsi->err = WSAEINVAL; 
1141                 return SOCKET_ERROR;
1142
1143         default:          
1144                 /* Netscape tries hard to use bogus ioctl 0x667e */
1145                 WARN(winsock, "\tunknown WS_IOCTL cmd (%08x)\n", cmd);
1146     }
1147     if( ioctl(pws->fd, newcmd, (char*)argp ) == 0 ) return 0;
1148     pwsi->err = (errno == EBADF) ? WSAENOTSOCK : wsaErrno(); 
1149   }
1150   return SOCKET_ERROR;
1151 }
1152
1153 /***********************************************************************
1154  *              ioctlsocket()           (WINSOCK.12)
1155  */
1156 INT16 WINAPI WINSOCK_ioctlsocket16(SOCKET16 s, UINT cmd, UINT *argp)
1157 {
1158     return (INT16)WINSOCK_ioctlsocket( s, cmd, argp );
1159 }
1160
1161
1162 /***********************************************************************
1163  *              listen()                (WSOCK32.13)
1164  */
1165 INT WINAPI WINSOCK_listen(SOCKET s, INT backlog)
1166 {
1167     ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s);
1168     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
1169
1170     TRACE(winsock, "(%08x): socket %04x, backlog %d\n", 
1171                             (unsigned)pwsi, s, backlog);
1172     if( _check_ws(pwsi, pws) )
1173     {
1174         if (listen(pws->fd, backlog) == 0)
1175         {
1176             if( !pws->psop )
1177             {
1178                 int  fd_flags = fcntl(pws->fd, F_GETFL, 0);
1179                 if( !(fd_flags & O_NONBLOCK) ) pws->flags |= WS_FD_ACCEPT;
1180             }
1181             pws->flags |= WS_FD_LISTENING;
1182             pws->flags &= ~(WS_FD_INACTIVE | WS_FD_CONNECT | WS_FD_CONNECTED); /* just in case */
1183             return 0;
1184         }
1185         pwsi->err = wsaErrno();
1186     }
1187     else if( pwsi ) pwsi->err = WSAENOTSOCK;
1188     return SOCKET_ERROR;
1189 }
1190
1191 /***********************************************************************
1192  *              listen()                (WINSOCK.13)
1193  */
1194 INT16 WINAPI WINSOCK_listen16(SOCKET16 s, INT16 backlog)
1195 {
1196     return (INT16)WINSOCK_listen( s, backlog );
1197 }
1198
1199
1200 /***********************************************************************
1201  *              recv()                  (WSOCK32.16)
1202  */
1203 INT WINAPI WINSOCK_recv(SOCKET s, char *buf, INT len, INT flags)
1204 {
1205     ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s);
1206     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
1207
1208     TRACE(winsock, "(%08x): socket %04x, buf %8x, len %d, "
1209                     "flags %d\n", (unsigned)pwsi, s, (unsigned)buf, 
1210                     len, flags);
1211     if( _check_ws(pwsi, pws) )
1212     {
1213         INT length;
1214         if ((length = recv(pws->fd, buf, len, flags)) >= 0) 
1215         { 
1216             TRACE(winsock, " -> %i bytes\n", length);
1217
1218             if( pws->psop && (pws->flags & (WS_FD_READ | WS_FD_CLOSE)) )
1219                 EVENT_AddIO( pws->fd, EVENT_IO_READ );  /* reenabler */
1220
1221             return length;
1222         }
1223         pwsi->err = wsaErrno();
1224     }
1225     else if( pwsi ) pwsi->err = WSAENOTSOCK;
1226     WARN(winsock, " -> ERROR\n");
1227     return SOCKET_ERROR;
1228 }
1229
1230 /***********************************************************************
1231  *              recv()                  (WINSOCK.16)
1232  */
1233 INT16 WINAPI WINSOCK_recv16(SOCKET16 s, char *buf, INT16 len, INT16 flags)
1234 {
1235     return (INT16)WINSOCK_recv( s, buf, len, flags );
1236 }
1237
1238
1239 /***********************************************************************
1240  *              recvfrom()              (WSOCK32.17)
1241  */
1242 INT WINAPI WINSOCK_recvfrom(SOCKET s, char *buf, INT len, INT flags, 
1243                                 struct sockaddr *from, INT *fromlen32)
1244 {
1245     ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s);
1246     LPWSINFO                 pwsi = wsi_find(GetCurrentTask());
1247 #ifdef HAVE_IPX
1248     struct ws_sockaddr_ipx*  from2 = (struct ws_sockaddr_ipx *)from;
1249 #endif
1250
1251     TRACE(winsock, "(%08x): socket %04x, ptr %08x, "
1252                     "len %d, flags %d\n", (unsigned)pwsi, s, (unsigned)buf,
1253                     len, flags);
1254 #if DEBUG_SOCKADDR
1255     if( from ) dump_sockaddr(from);
1256     else DUMP("from = NULL\n");
1257 #endif
1258
1259     if( _check_ws(pwsi, pws) )
1260     {
1261         int length;
1262
1263         if ((length = recvfrom(pws->fd, buf, len, flags, from, fromlen32)) >= 0)
1264         {
1265             TRACE(winsock, " -> %i bytes\n", length);
1266
1267             if( pws->psop && (pws->flags & (WS_FD_READ | WS_FD_CLOSE)) )
1268                 EVENT_AddIO( pws->fd, EVENT_IO_READ );  /* reenabler */
1269
1270 #ifdef HAVE_IPX
1271         if (from && ((struct sockaddr_ipx *)from)->sipx_family == AF_IPX) {
1272             from = (struct sockaddr *)
1273                                 malloc(fromlen32 ? *fromlen32 : sizeof(*from2));
1274             memcpy(from, from2, fromlen32 ? *fromlen32 : sizeof(*from2));
1275             from2->sipx_family = WS_AF_IPX;
1276             from2->sipx_network = ((struct sockaddr_ipx *)from)->sipx_network;
1277             from2->sipx_port = ((struct sockaddr_ipx *)from)->sipx_port;
1278             memcpy(from2->sipx_node,
1279                         ((struct sockaddr_ipx *)from)->sipx_node, IPX_NODE_LEN);
1280             free(from);
1281         }
1282 #endif
1283             return (INT16)length;
1284         }
1285         pwsi->err = wsaErrno();
1286     }
1287     else if( pwsi ) pwsi->err = WSAENOTSOCK;
1288     WARN(winsock, " -> ERROR\n");
1289 #ifdef HAVE_IPX
1290     if (from && ((struct sockaddr_ipx *)from)->sipx_family == AF_IPX) {
1291         from = (struct sockaddr *)
1292                                 malloc(fromlen32 ? *fromlen32 : sizeof(*from2));
1293         memcpy(from, from2, fromlen32 ? *fromlen32 : sizeof(*from2));
1294         from2->sipx_family = WS_AF_IPX;
1295         from2->sipx_network = ((struct sockaddr_ipx *)from)->sipx_network;
1296         from2->sipx_port = ((struct sockaddr_ipx *)from)->sipx_port;
1297         memcpy(from2->sipx_node,
1298                 ((struct sockaddr_ipx *)from)->sipx_node, IPX_NODE_LEN);
1299         free(from);
1300     }
1301 #endif
1302     return SOCKET_ERROR;
1303 }
1304
1305 /***********************************************************************
1306  *              recvfrom()              (WINSOCK.17)
1307  */
1308 INT16 WINAPI WINSOCK_recvfrom16(SOCKET16 s, char *buf, INT16 len, INT16 flags,
1309                                 struct sockaddr *from, INT16 *fromlen16)
1310 {
1311     INT fromlen32;
1312     INT *p = &fromlen32;
1313     INT retVal;
1314
1315     if( fromlen16 ) fromlen32 = *fromlen16; else p = NULL;
1316     retVal = WINSOCK_recvfrom( s, buf, len, flags, from, p );
1317     if( fromlen16 ) *fromlen16 = fromlen32;
1318     return (INT16)retVal;
1319 }
1320
1321 /***********************************************************************
1322  *              select()                (WINSOCK.18)(WSOCK32.18)
1323  */
1324 static INT __ws_select( BOOL b32, void *ws_readfds, void *ws_writefds, void *ws_exceptfds,
1325                           struct timeval *timeout )
1326 {
1327     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
1328         
1329     TRACE(winsock, "(%08x): read %8x, write %8x, excp %8x\n", 
1330     (unsigned) pwsi, (unsigned) ws_readfds, (unsigned) ws_writefds, (unsigned) ws_exceptfds);
1331
1332     if( pwsi )
1333     {
1334         int         highfd = 0;
1335         fd_set      readfds, writefds, exceptfds;
1336         fd_set     *p_read, *p_write, *p_except;
1337
1338         p_read = fd_set_import(&readfds, pwsi, ws_readfds, &highfd, b32);
1339         p_write = fd_set_import(&writefds, pwsi, ws_writefds, &highfd, b32);
1340         p_except = fd_set_import(&exceptfds, pwsi, ws_exceptfds, &highfd, b32);
1341
1342         if( (highfd = select(highfd + 1, p_read, p_write, p_except, timeout)) > 0 )
1343         {
1344             fd_set_export(pwsi, &readfds, p_except, ws_readfds, b32);
1345             fd_set_export(pwsi, &writefds, p_except, ws_writefds, b32);
1346
1347             if (p_except && ws_exceptfds)
1348             {
1349 #define wsfds16 ((ws_fd_set16*)ws_exceptfds)
1350 #define wsfds32 ((ws_fd_set32*)ws_exceptfds)
1351                 int i, j, count = (b32) ? wsfds32->fd_count : wsfds16->fd_count;
1352
1353                 for (i = j = 0; i < count; i++)
1354                 {
1355                     ws_socket *pws = (b32) ? (ws_socket *)WS_HANDLE2PTR(wsfds32->fd_array[i])
1356                                            : (ws_socket *)WS_HANDLE2PTR(wsfds16->fd_array[i]);
1357                     if( _check_ws(pwsi, pws) && FD_ISSET(pws->fd, &exceptfds) )
1358                     {
1359                         if( b32 )
1360                                 wsfds32->fd_array[j++] = wsfds32->fd_array[i];
1361                         else
1362                                 wsfds16->fd_array[j++] = wsfds16->fd_array[i];
1363                     }
1364                 }
1365                 if( b32 )
1366                     wsfds32->fd_count = j;
1367                 else
1368                     wsfds16->fd_count = j;
1369 #undef wsfds32
1370 #undef wsfds16
1371             }
1372             return highfd; 
1373         }
1374         if( ws_readfds ) ((ws_fd_set32*)ws_readfds)->fd_count = 0;
1375         if( ws_writefds ) ((ws_fd_set32*)ws_writefds)->fd_count = 0;
1376         if( ws_exceptfds ) ((ws_fd_set32*)ws_exceptfds)->fd_count = 0;
1377
1378         if( highfd == 0 ) return 0;
1379         pwsi->err = wsaErrno();
1380     } 
1381     return SOCKET_ERROR;
1382 }
1383
1384 INT16 WINAPI WINSOCK_select16(INT16 nfds, ws_fd_set16 *ws_readfds,
1385                               ws_fd_set16 *ws_writefds, ws_fd_set16 *ws_exceptfds,
1386                               struct timeval *timeout)
1387 {
1388     return (INT16)__ws_select( FALSE, ws_readfds, ws_writefds, ws_exceptfds, timeout );
1389 }
1390
1391 INT WINAPI WINSOCK_select(INT nfds, ws_fd_set32 *ws_readfds,
1392                               ws_fd_set32 *ws_writefds, ws_fd_set32 *ws_exceptfds,
1393                               struct timeval *timeout)
1394 {
1395     /* struct timeval is the same for both 32- and 16-bit code */
1396     return (INT)__ws_select( TRUE, ws_readfds, ws_writefds, ws_exceptfds, timeout );
1397 }
1398
1399
1400 /***********************************************************************
1401  *              send()                  (WSOCK32.19)
1402  */
1403 INT WINAPI WINSOCK_send(SOCKET s, char *buf, INT len, INT flags)
1404 {
1405     ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s);
1406     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
1407
1408     TRACE(winsock, "(%08x): socket %04x, ptr %08x, length %d, flags %d\n", 
1409                            (unsigned)pwsi, s, (unsigned) buf, len, flags);
1410     if( _check_ws(pwsi, pws) )
1411     {
1412         int     length;
1413
1414         if ((length = send(pws->fd, buf, len, flags)) < 0 ) 
1415         {
1416             pwsi->err = wsaErrno();
1417             if( pwsi->err == WSAEWOULDBLOCK && 
1418                 pws->psop && pws->flags & WS_FD_WRITE )
1419                 EVENT_AddIO( pws->fd, EVENT_IO_WRITE ); /* reenabler */
1420         }
1421         else return (INT16)length;
1422     }
1423     else if( pwsi ) pwsi->err = WSAENOTSOCK;
1424     return SOCKET_ERROR;
1425 }
1426
1427 /***********************************************************************
1428  *              send()                  (WINSOCK.19)
1429  */
1430 INT16 WINAPI WINSOCK_send16(SOCKET16 s, char *buf, INT16 len, INT16 flags)
1431 {
1432     return WINSOCK_send( s, buf, len, flags );
1433 }
1434
1435 /***********************************************************************
1436  *              sendto()                (WSOCK32.20)
1437  */
1438 INT WINAPI WINSOCK_sendto(SOCKET s, char *buf, INT len, INT flags,
1439                               struct sockaddr *to, INT tolen)
1440 {
1441     ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s);
1442     LPWSINFO                 pwsi = wsi_find(GetCurrentTask());
1443 #ifdef HAVE_IPX
1444     struct ws_sockaddr_ipx*  to2 = (struct ws_sockaddr_ipx *)to;
1445 #endif
1446
1447     TRACE(winsock, "(%08x): socket %04x, ptr %08x, length %d, flags %d\n",
1448                           (unsigned)pwsi, s, (unsigned) buf, len, flags);
1449     if( _check_ws(pwsi, pws) )
1450     {
1451         INT     length;
1452
1453         if (to && ((struct ws_sockaddr_ipx *)to)->sipx_family == WS_AF_PUP)
1454             ((struct ws_sockaddr_ipx *)to)->sipx_family = AF_UNSPEC;
1455 #ifdef HAVE_IPX
1456         else if (to &&
1457                 ((struct ws_sockaddr_ipx *)to)->sipx_family == WS_AF_IPX)
1458         {
1459             to = (struct sockaddr *) malloc(sizeof(struct sockaddr_ipx));
1460             memset(to, '\0', sizeof(struct sockaddr_ipx));
1461             ((struct sockaddr_ipx *)to)->sipx_family = AF_IPX;
1462             ((struct sockaddr_ipx *)to)->sipx_port = to2->sipx_port;
1463             ((struct sockaddr_ipx *)to)->sipx_network = to2->sipx_network;
1464             memcpy(((struct sockaddr_ipx *)to)->sipx_node,
1465                         to2->sipx_node, IPX_NODE_LEN);
1466             tolen = sizeof(struct sockaddr_ipx);
1467         }
1468 #endif
1469         if ((length = sendto(pws->fd, buf, len, flags, to, tolen)) < 0 )
1470         {
1471             pwsi->err = wsaErrno();
1472             if( pwsi->err == WSAEWOULDBLOCK &&
1473                 pws->psop && pws->flags & WS_FD_WRITE )
1474                 EVENT_AddIO( pws->fd, EVENT_IO_WRITE ); /* reenabler */
1475         } 
1476         else {
1477 #ifdef HAVE_IPX
1478             if (to && ((struct sockaddr_ipx *)to)->sipx_family == AF_IPX) {
1479                 free(to);
1480             }
1481 #endif
1482           return length;
1483         }
1484     }
1485     else if( pwsi ) pwsi->err = WSAENOTSOCK;
1486 #ifdef HAVE_IPX
1487     if (to && ((struct sockaddr_ipx *)to)->sipx_family == AF_IPX) {
1488         free(to);
1489     }
1490 #endif
1491     return SOCKET_ERROR;
1492 }
1493
1494 /***********************************************************************
1495  *              sendto()                (WINSOCK.20)
1496  */
1497 INT16 WINAPI WINSOCK_sendto16(SOCKET16 s, char *buf, INT16 len, INT16 flags,
1498                               struct sockaddr *to, INT16 tolen)
1499 {
1500     return (INT16)WINSOCK_sendto( s, buf, len, flags, to, tolen );
1501 }
1502
1503 /***********************************************************************
1504  *              setsockopt()            (WSOCK32.21)
1505  */
1506 INT WINAPI WINSOCK_setsockopt(SOCKET16 s, INT level, INT optname, 
1507                                   char *optval, INT optlen)
1508 {
1509     ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s);
1510     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
1511
1512     TRACE(winsock, "(%08x): socket %04x, lev %d, opt %d, ptr %08x, len %d\n",
1513                           (unsigned)pwsi, s, level, optname, (int) optval, optlen);
1514     if( _check_ws(pwsi, pws) )
1515     {
1516         struct  linger linger;
1517
1518         convert_sockopt(&level, &optname);
1519         if (optname == SO_LINGER && optval) {
1520                 /* yes, uses unsigned short in both win16/win32 */
1521                 linger.l_onoff  = ((UINT16*)optval)[0];
1522                 linger.l_linger = ((UINT16*)optval)[1];
1523                 /* FIXME: what is documented behavior if SO_LINGER optval
1524                    is null?? */
1525                 optval = (char*)&linger;
1526                 optlen = sizeof(struct linger);
1527         }
1528         if (setsockopt(pws->fd, level, optname, optval, optlen) == 0) return 0;
1529         pwsi->err = wsaErrno();
1530     }
1531     else if( pwsi ) pwsi->err = WSAENOTSOCK;
1532     return SOCKET_ERROR;
1533 }
1534
1535 /***********************************************************************
1536  *              setsockopt()            (WINSOCK.21)
1537  */
1538 INT16 WINAPI WINSOCK_setsockopt16(SOCKET16 s, INT16 level, INT16 optname,
1539                                   char *optval, INT16 optlen)
1540 {
1541     if( !optval ) return SOCKET_ERROR;
1542     return (INT16)WINSOCK_setsockopt( s, (UINT16)level, optname, optval, optlen );
1543 }
1544
1545
1546 /***********************************************************************
1547  *              shutdown()              (WSOCK32.22)
1548  */
1549 INT WINAPI WINSOCK_shutdown(SOCKET s, INT how)
1550 {
1551     ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s);
1552     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
1553
1554     TRACE(winsock, "(%08x): socket %04x, how %i\n",
1555                             (unsigned)pwsi, s, how );
1556     if( _check_ws(pwsi, pws) )
1557     {
1558         if( pws->psop )
1559             switch( how )
1560             {
1561                 case 0: /* drop receives */
1562                         if( pws->flags & (WS_FD_READ | WS_FD_CLOSE) )
1563                             EVENT_DeleteIO( pws->fd, EVENT_IO_READ );
1564                         pws->flags &= ~(WS_FD_READ | WS_FD_CLOSE);
1565 #ifdef SHUT_RD
1566                         how = SHUT_RD;
1567 #endif
1568                         break;
1569
1570                 case 1: /* drop sends */
1571                         if( pws->flags & WS_FD_WRITE )
1572                             EVENT_DeleteIO( pws->fd, EVENT_IO_WRITE );
1573                         pws->flags &= ~WS_FD_WRITE;
1574 #ifdef SHUT_WR
1575                         how = SHUT_WR;
1576 #endif
1577                         break;
1578
1579                 case 2: /* drop all */
1580 #ifdef SHUT_RDWR
1581                         how = SHUT_RDWR;
1582 #endif
1583                 default:
1584                         WSAAsyncSelect( s, 0, 0, 0 );
1585                         break;
1586             }
1587
1588         if (shutdown(pws->fd, how) == 0) 
1589         {
1590             if( how > 1 ) 
1591             {
1592                 pws->flags &= ~(WS_FD_CONNECTED | WS_FD_LISTENING);
1593                 pws->flags |= WS_FD_INACTIVE;
1594             }
1595             return 0;
1596         }
1597         pwsi->err = wsaErrno();
1598     } 
1599     else if( pwsi ) pwsi->err = WSAENOTSOCK;
1600     return SOCKET_ERROR;
1601 }
1602
1603 /***********************************************************************
1604  *              shutdown()              (WINSOCK.22)
1605  */
1606 INT16 WINAPI WINSOCK_shutdown16(SOCKET16 s, INT16 how)
1607 {
1608     return (INT16)WINSOCK_shutdown( s, how );
1609 }
1610
1611
1612 /***********************************************************************
1613  *              socket()                (WSOCK32.23)
1614  */
1615 SOCKET WINAPI WINSOCK_socket(INT af, INT type, INT protocol)
1616 {
1617   LPWSINFO      pwsi = wsi_find(GetCurrentTask());
1618
1619   TRACE(winsock, "(%08x): af=%d type=%d protocol=%d\n", 
1620                           (unsigned)pwsi, af, type, protocol);
1621
1622   if( pwsi )
1623   {
1624     int         sock;
1625
1626     /* check the socket family */
1627     switch(af) 
1628     {
1629 #ifdef HAVE_IPX
1630         case WS_AF_IPX: af = AF_IPX;
1631 #endif
1632         case AF_INET:
1633         case AF_UNSPEC: break;
1634         default:        pwsi->err = WSAEAFNOSUPPORT; 
1635                         return INVALID_SOCKET;
1636     }
1637
1638     /* check the socket type */
1639     switch(type) 
1640     {
1641         case SOCK_STREAM:
1642         case SOCK_DGRAM:
1643         case SOCK_RAW:  break;
1644         default:        pwsi->err = WSAESOCKTNOSUPPORT; 
1645                         return INVALID_SOCKET;
1646     }
1647
1648     /* check the protocol type */
1649     if ( protocol < 0 )  /* don't support negative values */
1650     { pwsi->err = WSAEPROTONOSUPPORT; return INVALID_SOCKET; }
1651
1652     if ( af == AF_UNSPEC)  /* did they not specify the address family? */
1653         switch(protocol) 
1654         {
1655           case IPPROTO_TCP:
1656              if (type == SOCK_STREAM) { af = AF_INET; break; }
1657           case IPPROTO_UDP:
1658              if (type == SOCK_DGRAM)  { af = AF_INET; break; }
1659           default: pwsi->err = WSAEPROTOTYPE; return INVALID_SOCKET;
1660         }
1661
1662     if ((sock = socket(af, type, protocol)) >= 0) 
1663     {
1664         ws_socket*      pnew = wsi_alloc_socket(pwsi, sock);
1665
1666         TRACE(winsock,"\tcreated %i (handle %04x)\n", sock, (UINT16)WS_PTR2HANDLE(pnew));
1667
1668         if( pnew ) 
1669         {
1670             pnew->flags |= WS_FD_INACTIVE;
1671             return (SOCKET16)WS_PTR2HANDLE(pnew);
1672         }
1673         
1674         close(sock);
1675         pwsi->err = WSAENOBUFS;
1676         return INVALID_SOCKET;
1677     }
1678
1679     if (errno == EPERM) /* raw socket denied */
1680     {
1681         WARN(winsock, "WS_SOCKET: not enough privileges\n");
1682         pwsi->err = WSAESOCKTNOSUPPORT;
1683     } else pwsi->err = wsaErrno();
1684   }
1685  
1686   WARN(winsock, "\t\tfailed!\n");
1687   return INVALID_SOCKET;
1688 }
1689
1690 /***********************************************************************
1691  *              socket()                (WINSOCK.23)
1692  */
1693 SOCKET16 WINAPI WINSOCK_socket16(INT16 af, INT16 type, INT16 protocol)
1694 {
1695     return (SOCKET16)WINSOCK_socket( af, type, protocol );
1696 }
1697     
1698
1699 /* ----------------------------------- DNS services
1700  *
1701  * IMPORTANT: 16-bit API structures have SEGPTR pointers inside them.
1702  * Also, we have to use wsock32 stubs to convert structures and
1703  * error codes from Unix to WSA, hence there is no direct mapping in 
1704  * the relay32/wsock32.spec.
1705  */
1706
1707 static char*    NULL_STRING = "NULL";
1708
1709 /***********************************************************************
1710  *              gethostbyaddr()         (WINSOCK.51)(WSOCK32.51)
1711  */
1712 static struct WIN_hostent* __ws_gethostbyaddr(const char *addr, int len, int type, int dup_flag)
1713 {
1714     LPWSINFO            pwsi = wsi_find(GetCurrentTask());
1715
1716     if( pwsi )
1717     {
1718         struct hostent* host;
1719         if( (host = gethostbyaddr(addr, len, type)) != NULL )
1720             if( WS_dup_he(pwsi, host, dup_flag) )
1721                 return (struct WIN_hostent*)(pwsi->he);
1722             else 
1723                 pwsi->err = WSAENOBUFS;
1724         else 
1725             pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
1726     }
1727     return NULL;
1728 }
1729
1730 SEGPTR WINAPI WINSOCK_gethostbyaddr16(const char *addr, INT16 len, INT16 type)
1731 {
1732     struct WIN_hostent* retval;
1733     TRACE(winsock, "ptr %08x, len %d, type %d\n",
1734                             (unsigned) addr, len, type);
1735     retval = __ws_gethostbyaddr( addr, len, type, WS_DUP_SEGPTR );
1736     return retval ? SEGPTR_GET(retval) : ((SEGPTR)NULL);
1737 }
1738
1739 struct WIN_hostent* WINAPI WINSOCK_gethostbyaddr(const char *addr, INT len,
1740                                                 INT type)
1741 {
1742     TRACE(winsock, "ptr %08x, len %d, type %d\n",
1743                              (unsigned) addr, len, type);
1744     return __ws_gethostbyaddr(addr, len, type, WS_DUP_LINEAR);
1745 }
1746
1747 /***********************************************************************
1748  *              gethostbyname()         (WINSOCK.52)(WSOCK32.52)
1749  */
1750 static struct WIN_hostent * __ws_gethostbyname(const char *name, int dup_flag)
1751 {
1752     LPWSINFO              pwsi = wsi_find(GetCurrentTask());
1753
1754     if( pwsi )
1755     {
1756         struct hostent*     host;
1757         if( (host = gethostbyname(name)) != NULL )
1758              if( WS_dup_he(pwsi, host, dup_flag) )
1759                  return (struct WIN_hostent*)(pwsi->he);
1760              else pwsi->err = WSAENOBUFS;
1761         else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
1762     }
1763     return NULL;
1764 }
1765
1766 SEGPTR WINAPI WINSOCK_gethostbyname16(const char *name)
1767 {
1768     struct WIN_hostent* retval;
1769     TRACE(winsock, "%s\n", (name)?name:NULL_STRING);
1770     retval = __ws_gethostbyname( name, WS_DUP_SEGPTR );
1771     return (retval)? SEGPTR_GET(retval) : ((SEGPTR)NULL) ;
1772 }
1773
1774 struct WIN_hostent* WINAPI WINSOCK_gethostbyname(const char* name)
1775 {
1776     TRACE(winsock, "%s\n", (name)?name:NULL_STRING);
1777     return __ws_gethostbyname( name, WS_DUP_LINEAR );
1778 }
1779
1780
1781 /***********************************************************************
1782  *              getprotobyname()        (WINSOCK.53)(WSOCK32.53)
1783  */
1784 static struct WIN_protoent* __ws_getprotobyname(const char *name, int dup_flag)
1785 {
1786     LPWSINFO              pwsi = wsi_find(GetCurrentTask());
1787
1788     if( pwsi )
1789     {
1790         struct protoent*     proto;
1791         if( (proto = getprotobyname(name)) != NULL )
1792             if( WS_dup_pe(pwsi, proto, dup_flag) )
1793                 return (struct WIN_protoent*)(pwsi->pe);
1794             else pwsi->err = WSAENOBUFS;
1795         else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
1796     }
1797     return NULL;
1798 }
1799
1800 SEGPTR WINAPI WINSOCK_getprotobyname16(const char *name)
1801 {
1802     struct WIN_protoent* retval;
1803     TRACE(winsock, "%s\n", (name)?name:NULL_STRING);
1804     retval = __ws_getprotobyname(name, WS_DUP_SEGPTR);
1805     return retval ? SEGPTR_GET(retval) : ((SEGPTR)NULL);
1806 }
1807
1808 struct WIN_protoent* WINAPI WINSOCK_getprotobyname(const char* name)
1809 {
1810     TRACE(winsock, "%s\n", (name)?name:NULL_STRING);
1811     return __ws_getprotobyname(name, WS_DUP_LINEAR);
1812 }
1813
1814
1815 /***********************************************************************
1816  *              getprotobynumber()      (WINSOCK.54)(WSOCK32.54)
1817  */
1818 static struct WIN_protoent* __ws_getprotobynumber(int number, int dup_flag)
1819 {
1820     LPWSINFO              pwsi = wsi_find(GetCurrentTask());
1821
1822     if( pwsi )
1823     {
1824         struct protoent*     proto;
1825         if( (proto = getprotobynumber(number)) != NULL )
1826             if( WS_dup_pe(pwsi, proto, dup_flag) )
1827                 return (struct WIN_protoent*)(pwsi->pe);
1828             else pwsi->err = WSAENOBUFS;
1829         else pwsi->err = WSANO_DATA;
1830     }
1831     return NULL;
1832 }
1833
1834 SEGPTR WINAPI WINSOCK_getprotobynumber16(INT16 number)
1835 {
1836     struct WIN_protoent* retval;
1837     TRACE(winsock, "%i\n", number);
1838     retval = __ws_getprotobynumber(number, WS_DUP_SEGPTR);
1839     return retval ? SEGPTR_GET(retval) : ((SEGPTR)NULL);
1840 }
1841
1842 struct WIN_protoent* WINAPI WINSOCK_getprotobynumber(INT number)
1843 {
1844     TRACE(winsock, "%i\n", number);
1845     return __ws_getprotobynumber(number, WS_DUP_LINEAR);
1846 }
1847
1848
1849 /***********************************************************************
1850  *              getservbyname()         (WINSOCK.55)(WSOCK32.55)
1851  */
1852 struct WIN_servent* __ws_getservbyname(const char *name, const char *proto, int dup_flag)
1853 {
1854     LPWSINFO              pwsi = wsi_find(GetCurrentTask());
1855
1856     if( pwsi )
1857     {
1858         struct servent*     serv;
1859         int i = wsi_strtolo( pwsi, name, proto );
1860
1861         if( i )
1862             if( (serv = getservbyname(pwsi->buffer, pwsi->buffer + i)) != NULL )
1863                 if( WS_dup_se(pwsi, serv, dup_flag) )
1864                     return (struct WIN_servent*)(pwsi->se);
1865                 else pwsi->err = WSAENOBUFS;
1866             else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
1867         else pwsi->err = WSAENOBUFS;
1868     }
1869     return NULL;
1870 }
1871
1872 SEGPTR WINAPI WINSOCK_getservbyname16(const char *name, const char *proto)
1873 {
1874     struct WIN_servent* retval;
1875     TRACE(winsock, "'%s', '%s'\n",
1876                             (name)?name:NULL_STRING, (proto)?proto:NULL_STRING);
1877     retval = __ws_getservbyname(name, proto, WS_DUP_SEGPTR);
1878     return retval ? SEGPTR_GET(retval) : ((SEGPTR)NULL);
1879 }
1880
1881 struct WIN_servent* WINAPI WINSOCK_getservbyname(const char *name, const char *proto)
1882 {
1883     TRACE(winsock, "'%s', '%s'\n",
1884                             (name)?name:NULL_STRING, (proto)?proto:NULL_STRING);
1885     return __ws_getservbyname(name, proto, WS_DUP_LINEAR);
1886 }
1887
1888
1889 /***********************************************************************
1890  *              getservbyport()         (WINSOCK.56)(WSOCK32.56)
1891  */
1892 static struct WIN_servent* __ws_getservbyport(int port, const char* proto, int dup_flag)
1893 {
1894     LPWSINFO              pwsi = wsi_find(GetCurrentTask());
1895
1896     if( pwsi )
1897     {
1898         struct servent*     serv;
1899         int i = wsi_strtolo( pwsi, proto, NULL );
1900
1901         if( i )
1902             if( (serv = getservbyport(port, pwsi->buffer)) != NULL )
1903                 if( WS_dup_se(pwsi, serv, dup_flag) )
1904                     return (struct WIN_servent*)(pwsi->se);
1905                 else pwsi->err = WSAENOBUFS;
1906             else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno();
1907         else pwsi->err = WSAENOBUFS;
1908     }
1909     return NULL;
1910 }
1911
1912 SEGPTR WINAPI WINSOCK_getservbyport16(INT16 port, const char *proto)
1913 {
1914     struct WIN_servent* retval;
1915     TRACE(winsock, "%i, '%s'\n",
1916                             (int)port, (proto)?proto:NULL_STRING);
1917     retval = __ws_getservbyport(port, proto, WS_DUP_SEGPTR);
1918     return retval ? SEGPTR_GET(retval) : ((SEGPTR)NULL);
1919 }
1920
1921 struct WIN_servent* WINAPI WINSOCK_getservbyport(INT port, const char *proto)
1922 {
1923     TRACE(winsock, "%i, '%s'\n",
1924                             (int)port, (proto)?proto:NULL_STRING);
1925     return __ws_getservbyport(port, proto, WS_DUP_LINEAR);
1926 }
1927
1928
1929 /***********************************************************************
1930  *              gethostname()           (WSOCK32.57)
1931  */
1932 INT WINAPI WINSOCK_gethostname(char *name, INT namelen)
1933 {
1934     LPWSINFO              pwsi = wsi_find(GetCurrentTask());
1935
1936     TRACE(winsock, "(%08x): name %s, len %d\n",
1937                           (unsigned)pwsi, (name)?name:NULL_STRING, namelen);
1938     if( pwsi )
1939     {
1940         if (gethostname(name, namelen) == 0) return 0;
1941         pwsi->err = (errno == EINVAL) ? WSAEFAULT : wsaErrno();
1942     }
1943     return SOCKET_ERROR;
1944 }
1945
1946 /***********************************************************************
1947  *              gethostname()           (WINSOCK.57)
1948  */
1949 INT16 WINAPI WINSOCK_gethostname16(char *name, INT16 namelen)
1950 {
1951     return (INT16)WINSOCK_gethostname(name, namelen);
1952 }
1953
1954
1955 /* ------------------------------------- Windows sockets extensions -- *
1956  *                                                                     *
1957  * ------------------------------------------------------------------- */
1958 /***********************************************************************
1959  *      WSAAsyncSelect()                (WINSOCK.101)(WSOCK32.101)
1960  */
1961
1962 static ws_select_op* __ws_select_list = NULL;
1963
1964 BOOL WINSOCK_HandleIO( int* max_fd, int num_pending, 
1965                          fd_set pending_set[3], fd_set event_set[3] )
1966 {
1967     /* This function is called by the event dispatcher
1968      * with the pending_set[] containing the result of select() and
1969      * the event_set[] containing all fd that are being watched */
1970
1971     ws_select_op*       psop = __ws_select_list;
1972     BOOL                bPost = FALSE;
1973     DWORD               dwEvent, dwErrBytes;
1974     int                 num_posted;
1975
1976     TRACE(winsock,"%i pending descriptors\n", num_pending );
1977
1978     for( num_posted = dwEvent = 0 ; psop; psop = psop->next )
1979     {
1980         unsigned        flags = psop->pws->flags;
1981         int             fd = psop->pws->fd;
1982         int             r, w, e;
1983
1984         w = 0;
1985         if( (r = FD_ISSET( fd, &pending_set[EVENT_IO_READ] )) ||
1986             (w = FD_ISSET( fd, &pending_set[EVENT_IO_WRITE] )) ||
1987             (e = FD_ISSET( fd, &pending_set[EVENT_IO_EXCEPT] )) )
1988         {
1989             /* This code removes WS_FD flags on one-shot events (WS_FD_CLOSE, 
1990              * WS_FD_CONNECT), otherwise it clears descriptors in the io_set.
1991              * Reenabling calls turn them back on.
1992              */
1993
1994             TRACE(winsock,"\tchecking psop = 0x%08x\n", (unsigned) psop );
1995
1996             num_pending--;
1997
1998             /* Now figure out what kind of event we've got. The worst problem
1999              * we have to contend with is that some out of control applications 
2000              * really want to use mutually exclusive AsyncSelect() flags all at
2001              * the same time.
2002              */
2003
2004             if((flags & WS_FD_ACCEPT) && (flags & WS_FD_LISTENING))
2005             {
2006                 /* WS_FD_ACCEPT is valid only if the socket is in the
2007                  * listening state */
2008
2009                 FD_CLR( fd, &event_set[EVENT_IO_WRITE] );
2010                 if( r )
2011                 {
2012                     FD_CLR( fd, &event_set[EVENT_IO_READ] ); /* reenabled by the next accept() */
2013                     dwEvent = WSAMAKESELECTREPLY( WS_FD_ACCEPT, 0 );
2014                     bPost = TRUE;
2015                 } 
2016                 else continue;
2017             }
2018             else if( flags & WS_FD_CONNECT )
2019             {
2020                 /* connecting socket */
2021
2022                 if( w || (w = FD_ISSET( fd, &pending_set[EVENT_IO_WRITE] )) )
2023                 {
2024                     /* ready to write means that socket is connected 
2025                      *
2026                      * FIXME: Netscape calls AsyncSelect( s, ... WS_FD_CONNECT .. )
2027                      * right after s = socket() and somehow "s" becomes writeable 
2028                      * before it goes through connect()!?!?
2029                      */
2030
2031                     psop->pws->flags |= WS_FD_CONNECTED;
2032                     psop->pws->flags &= ~(WS_FD_CONNECT | WS_FD_INACTIVE);
2033                     dwEvent = WSAMAKESELECTREPLY( WS_FD_CONNECT, 0 );
2034
2035                     if( flags & (WS_FD_READ | WS_FD_CLOSE))
2036                         FD_SET( fd, &event_set[EVENT_IO_READ] );
2037                     else 
2038                         FD_CLR( fd, &event_set[EVENT_IO_READ] );
2039                     if( flags & WS_FD_WRITE ) 
2040                         FD_SET( fd, &event_set[EVENT_IO_WRITE] );
2041                     else 
2042                         FD_CLR( fd, &event_set[EVENT_IO_WRITE] );
2043                     bPost = TRUE;
2044                 }
2045                 else if( r )
2046                 {
2047                     /* failure - do read() to get correct errno */
2048
2049                     if( read( fd, &dwErrBytes, sizeof(dwErrBytes) ) == -1 )
2050                     {
2051                         dwEvent = WSAMAKESELECTREPLY( WS_FD_CONNECT, wsaErrno() );
2052                         bPost = TRUE;
2053                     }
2054                 }
2055                 /* otherwise bPost stays FALSE, should probably clear event_set  */
2056             }
2057             else 
2058             {
2059                 /* connected socket, no WS_FD_OOB code for now. */
2060
2061                 if( flags & WS_FD_WRITE &&
2062                    (w || (w = FD_ISSET( fd, &pending_set[EVENT_IO_WRITE] ))) )
2063                 {
2064                     /* this will be reenabled when send() or sendto() fail with
2065                      * WSAEWOULDBLOCK */
2066
2067                     if( PostMessageA( psop->hWnd, psop->uMsg, (WPARAM)WS_PTR2HANDLE(psop->pws), 
2068                                       (LPARAM)WSAMAKESELECTREPLY( WS_FD_WRITE, 0 ) ) )
2069                     {
2070                         TRACE(winsock, "\t    hwnd %04x - %04x, %08x\n",
2071                                 psop->hWnd, psop->uMsg, (unsigned)MAKELONG(WS_FD_WRITE, 0) );
2072                         FD_CLR( fd, &event_set[EVENT_IO_WRITE] );
2073                         num_posted++;
2074                     }
2075                 }
2076
2077                 if( r && (flags & (WS_FD_READ | WS_FD_CLOSE)) )
2078                 {
2079                     int val = (flags & WS_FD_RAW);
2080
2081                      /* WS_FD_RAW is set by the WSAAsyncSelect() init */
2082
2083                     bPost = TRUE;
2084                     if( !val && ioctl( fd, FIONREAD, (char*)&dwErrBytes) == -1 )
2085                     {
2086                         /* weirdness */
2087
2088                         dwEvent = WSAMAKESELECTREPLY( WS_FD_READ, wsaErrno() );
2089                     }
2090                     else if( val || dwErrBytes )
2091                     {
2092                         /* got pending data, will be reenabled by recv() or recvfrom() */
2093
2094                         FD_CLR( fd, &event_set[EVENT_IO_READ] );
2095                         dwEvent = WSAMAKESELECTREPLY( WS_FD_READ, 0 );
2096                     }
2097                     else
2098                     {
2099                         /* 0 bytes to read - connection reset by peer? */
2100
2101                         do
2102                             val = read( fd, (char*)&dwErrBytes, sizeof(dwErrBytes));
2103                         while( errno == EINTR );
2104                         if( errno != EWOULDBLOCK )
2105                         {
2106                             switch( val )
2107                             {
2108                                 case  0: errno = ENETDOWN;      /* soft reset, fall through */
2109                                 case -1:                        /* hard reset */
2110                                          dwEvent = WSAMAKESELECTREPLY( WS_FD_CLOSE, wsaErrno() );
2111                                          break;
2112
2113                                 default: bPost = FALSE;
2114                                          continue;              /* FIXME: this is real bad */
2115                             }
2116                         }
2117                         else { bPost = FALSE; continue; }       /* more weirdness */
2118
2119                         /* this is it, this socket is closed */
2120
2121                         psop->pws->flags &= ~(WS_FD_READ | WS_FD_CLOSE | WS_FD_WRITE);
2122                         FD_CLR( fd, &event_set[EVENT_IO_READ] );
2123                         FD_CLR( fd, &event_set[EVENT_IO_WRITE] );
2124
2125                         if( *max_fd == (fd + 1) ) (*max_fd)--;
2126                     }
2127                 }
2128             }
2129
2130             if( bPost )
2131             {
2132                 TRACE(winsock, "\t    hwnd %04x - %04x, %08x\n", 
2133                                 psop->hWnd, psop->uMsg, (unsigned)dwEvent );
2134                 PostMessageA( psop->hWnd, psop->uMsg, 
2135                               (WPARAM)WS_PTR2HANDLE(psop->pws), (LPARAM)dwEvent );
2136                 bPost = FALSE;
2137                 num_posted++;
2138             }
2139         }
2140         if( num_pending <= 0 ) break;
2141     }
2142
2143     TRACE(winsock, "\tdone, %i posted events\n", num_posted );
2144     return ( num_posted ) ? TRUE : FALSE;
2145 }
2146
2147 INT WINAPI WSAAsyncSelect(SOCKET s, HWND hWnd, UINT uMsg, UINT lEvent)
2148 {
2149     ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s);
2150     LPWSINFO      pwsi = wsi_find(GetCurrentTask());
2151
2152     TRACE(winsock, "(%08x): %04x, hWnd %04x, uMsg %08x, event %08x\n",
2153                           (unsigned)pwsi, (SOCKET16)s, (HWND16)hWnd, uMsg, (unsigned)lEvent );
2154     if( _check_ws(pwsi, pws) )
2155     {
2156         ws_select_op* psop;
2157
2158         if( (psop = pws->psop) )
2159         {
2160             /* delete previous control struct */
2161
2162             if( psop == __ws_select_list )
2163                 __ws_select_list = psop->next;
2164             else
2165                 psop->prev->next = psop->next; 
2166             if( psop->next ) psop->next->prev = psop->prev;
2167
2168             if( pws->flags & (WS_FD_ACCEPT | WS_FD_CONNECT | WS_FD_READ | WS_FD_CLOSE) )
2169                 EVENT_DeleteIO( pws->fd, EVENT_IO_READ );
2170             if( pws->flags & (WS_FD_CONNECT | WS_FD_WRITE) )
2171                 EVENT_DeleteIO( pws->fd, EVENT_IO_WRITE );
2172
2173             TRACE(winsock,"\tremoving psop = 0x%08x\n", (unsigned) psop );
2174
2175             WS_FREE( pws->psop );
2176             pws->flags &= ~(WS_FD_RAW | WS_FD_ACCEPT | WS_FD_CONNECT | 
2177                             WS_FD_READ | WS_FD_WRITE | WS_FD_CLOSE);
2178             pws->psop = NULL;
2179         }
2180
2181         if( lEvent )
2182         {
2183             psop = (ws_select_op*)WS_ALLOC(sizeof(ws_select_op));
2184             if( psop )
2185             {
2186                 int sock_type, bytes = sizeof(int);
2187
2188                 WINSOCK_unblock_io( pws->fd, TRUE );
2189
2190                 psop->prev = NULL;
2191                 psop->next = __ws_select_list;
2192                 if( __ws_select_list )
2193                     __ws_select_list->prev = psop;
2194                 __ws_select_list = psop;
2195                 
2196                 psop->pws = pws;
2197                 psop->hWnd = hWnd;
2198                 psop->uMsg = uMsg;
2199
2200                 pws->psop = psop;
2201                 pws->flags |= (0x0000FFFF & lEvent);
2202                 getsockopt(pws->fd, SOL_SOCKET, SO_TYPE, &sock_type, &bytes);
2203                 if( sock_type == SOCK_RAW ) pws->flags |= WS_FD_RAW;
2204
2205                 if( lEvent & (WS_FD_ACCEPT | WS_FD_CONNECT | WS_FD_READ | WS_FD_CLOSE) )
2206                     EVENT_AddIO( pws->fd, EVENT_IO_READ );
2207                 if( lEvent & (WS_FD_CONNECT | WS_FD_WRITE) )
2208                     EVENT_AddIO( pws->fd, EVENT_IO_WRITE );
2209
2210                 /* TODO: handle WS_FD_ACCEPT right away if the socket is readable */
2211
2212                 TRACE(winsock,"\tcreating psop = 0x%08x\n", (unsigned)psop );
2213
2214                 return 0; /* success */
2215             }
2216             else pwsi->err = WSAENOBUFS;
2217         } 
2218         else return 0;
2219     } 
2220     else if( pwsi ) pwsi->err = WSAEINVAL;
2221     return SOCKET_ERROR; 
2222 }
2223
2224 INT16 WINAPI WSAAsyncSelect16(SOCKET16 s, HWND16 hWnd, UINT16 wMsg, UINT lEvent)
2225 {
2226     return (INT16)WSAAsyncSelect( s, hWnd, wMsg, lEvent );
2227 }
2228
2229
2230 /***********************************************************************
2231  *      __WSAFDIsSet()                  (WINSOCK.151)
2232  */
2233 INT16 WINAPI __WSAFDIsSet16(SOCKET16 s, ws_fd_set16 *set)
2234 {
2235   int i = set->fd_count;
2236   
2237   TRACE(winsock, "(%d,%8lx(%i))\n", s,(unsigned long)set, i);
2238     
2239   while (i--)
2240       if (set->fd_array[i] == s) return 1;
2241   return 0;
2242 }                                                            
2243
2244 /***********************************************************************
2245  *      __WSAFDIsSet()                  (WSOCK32.151)
2246  */
2247 INT WINAPI __WSAFDIsSet(SOCKET s, ws_fd_set32 *set)
2248 {
2249   int i = set->fd_count;
2250
2251   TRACE(winsock, "(%d,%8lx(%i))\n", s,(unsigned long)set, i);
2252
2253   while (i--)
2254       if (set->fd_array[i] == s) return 1;
2255   return 0;
2256 }
2257
2258 /***********************************************************************
2259  *      WSAIsBlocking()                 (WINSOCK.114)(WSOCK32.114)
2260  */
2261 BOOL WINAPI WSAIsBlocking(void)
2262 {
2263   /* By default WinSock should set all its sockets to non-blocking mode
2264    * and poll in PeekMessage loop when processing "blocking" ones. This 
2265    * function is supposed to tell if the program is in this loop. Our 
2266    * blocking calls are truly blocking so we always return FALSE.
2267    *
2268    * Note: It is allowed to call this function without prior WSAStartup().
2269    */
2270
2271   TRACE(winsock, "\n");
2272   return FALSE;
2273 }
2274
2275 /***********************************************************************
2276  *      WSACancelBlockingCall()         (WINSOCK.113)(WSOCK32.113)
2277  */
2278 INT WINAPI WSACancelBlockingCall(void)
2279 {
2280   LPWSINFO              pwsi = wsi_find(GetCurrentTask());
2281
2282   TRACE(winsock, "(%08x)\n", (unsigned)pwsi);
2283
2284   if( pwsi ) return 0;
2285   return SOCKET_ERROR;
2286 }
2287
2288
2289 /***********************************************************************
2290  *      WSASetBlockingHook16()          (WINSOCK.109)
2291  */
2292 FARPROC16 WINAPI WSASetBlockingHook16(FARPROC16 lpBlockFunc)
2293 {
2294   FARPROC16             prev;
2295   LPWSINFO              pwsi = wsi_find(GetCurrentTask());
2296
2297   TRACE(winsock, "(%08x): hook %08x\n", 
2298                (unsigned)pwsi, (unsigned) lpBlockFunc);
2299   if( pwsi ) 
2300   { 
2301       prev = (FARPROC16)pwsi->blocking_hook; 
2302       pwsi->blocking_hook = (DWORD)lpBlockFunc; 
2303       pwsi->flags &= ~WSI_BLOCKINGHOOK;
2304       return prev; 
2305   }
2306   return 0;
2307 }
2308
2309
2310 /***********************************************************************
2311  *      WSASetBlockingHook32()
2312  */
2313 FARPROC WINAPI WSASetBlockingHook(FARPROC lpBlockFunc)
2314 {
2315   FARPROC             prev;
2316   LPWSINFO              pwsi = wsi_find(GetCurrentTask());
2317
2318   TRACE(winsock, "(%08x): hook %08x\n",
2319                (unsigned)pwsi, (unsigned) lpBlockFunc);
2320   if( pwsi ) {
2321       prev = (FARPROC)pwsi->blocking_hook;
2322       pwsi->blocking_hook = (DWORD)lpBlockFunc;
2323       pwsi->flags |= WSI_BLOCKINGHOOK;
2324       return prev;
2325   }
2326   return NULL;
2327 }
2328
2329
2330 /***********************************************************************
2331  *      WSAUnhookBlockingHook16()       (WINSOCK.110)
2332  */
2333 INT16 WINAPI WSAUnhookBlockingHook16(void)
2334 {
2335     LPWSINFO              pwsi = wsi_find(GetCurrentTask());
2336
2337     TRACE(winsock, "(%08x)\n", (unsigned)pwsi);
2338     if( pwsi ) return (INT16)(pwsi->blocking_hook = 0);
2339     return SOCKET_ERROR;
2340 }
2341
2342
2343 /***********************************************************************
2344  *      WSAUnhookBlockingHook32()
2345  */
2346 INT WINAPI WSAUnhookBlockingHook(void)
2347 {
2348     LPWSINFO              pwsi = wsi_find(GetCurrentTask());
2349
2350     TRACE(winsock, "(%08x)\n", (unsigned)pwsi);
2351     if( pwsi )
2352     {
2353         pwsi->blocking_hook = 0;
2354         pwsi->flags &= ~WSI_BLOCKINGHOOK;
2355         return 0;
2356     }
2357     return SOCKET_ERROR;
2358 }
2359
2360 /*
2361  *      TCP/IP action codes.
2362  */
2363
2364
2365 #define WSCNTL_TCPIP_QUERY_INFO             0x00000000
2366 #define WSCNTL_TCPIP_SET_INFO               0x00000001
2367 #define WSCNTL_TCPIP_ICMP_ECHO              0x00000002
2368 #define WSCNTL_TCPIP_TEST                   0x00000003
2369
2370
2371 /***********************************************************************
2372  *      WsControl()
2373  *
2374  * WsControl seems to be an undocumented Win95 function. A lot of 
2375  * discussion about WsControl can be found on the net, e.g.
2376  * Subject:      Re: WSOCK32.DLL WsControl Exported Function
2377  * From:         "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
2378  * Date:         1997/08/17
2379  */
2380
2381 DWORD WINAPI WsControl(DWORD protocoll,DWORD action,
2382                       LPVOID inbuf,LPDWORD inbuflen,
2383                       LPVOID outbuf,LPDWORD outbuflen) 
2384 {
2385
2386   switch (action) {
2387   case WSCNTL_TCPIP_ICMP_ECHO:
2388     {
2389       unsigned int addr = *(unsigned int*)inbuf;
2390 #if 0
2391       int timeout= *(unsigned int*)(inbuf+4);
2392       short x1 = *(unsigned short*)(inbuf+8);
2393       short sendbufsize = *(unsigned short*)(inbuf+10);
2394       char x2 = *(unsigned char*)(inbuf+12);
2395       char ttl = *(unsigned char*)(inbuf+13);
2396       char service = *(unsigned char*)(inbuf+14);
2397       char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
2398 #endif      
2399       
2400       FIXME(winsock,"(ICMP_ECHO) to 0x%08x stub \n", addr);
2401       break;
2402     }
2403   default:
2404     FIXME(winsock,"(%lx,%lx,%p,%p,%p,%p) stub\n",
2405           protocoll,action,inbuf,inbuflen,outbuf,outbuflen);
2406   }
2407   return FALSE;
2408 }
2409 /*********************************************************
2410  *       WS_s_perror         WSOCK32.1108 
2411  */
2412 void WINAPI WS_s_perror(LPCSTR message)
2413 {
2414     FIXME(winsock,"(%s): stub\n",message);
2415     return;
2416 }
2417
2418
2419 /* ----------------------------------- end of API stuff */
2420
2421 /* ----------------------------------- helper functions -
2422  *
2423  * TODO: Merge WS_dup_..() stuff into one function that
2424  * would operate with a generic structure containing internal
2425  * pointers (via a template of some kind).
2426  */
2427
2428 static int list_size(char** l, int item_size)
2429 {
2430   int i,j = 0;
2431   if(l)
2432   { for(i=0;l[i];i++) 
2433         j += (item_size) ? item_size : strlen(l[i]) + 1;
2434     j += (i + 1) * sizeof(char*); }
2435   return j;
2436 }
2437
2438 static int list_dup(char** l_src, char* ref, char* base, int item_size)
2439
2440    /* base is either either equal to ref or 0 or SEGPTR */
2441
2442    char*                p = ref;
2443    char**               l_to = (char**)ref;
2444    int                  i,j,k;
2445
2446    for(j=0;l_src[j];j++) ;
2447    p += (j + 1) * sizeof(char*);
2448    for(i=0;i<j;i++)
2449    { l_to[i] = base + (p - ref);
2450      k = ( item_size ) ? item_size : strlen(l_src[i]) + 1;
2451      memcpy(p, l_src[i], k); p += k; }
2452    l_to[i] = NULL;
2453    return (p - ref);
2454 }
2455
2456 /* ----- hostent */
2457
2458 static int hostent_size(struct hostent* p_he)
2459 {
2460   int size = 0;
2461   if( p_he )
2462   { size  = sizeof(struct hostent); 
2463     size += strlen(p_he->h_name) + 1;
2464     size += list_size(p_he->h_aliases, 0);  
2465     size += list_size(p_he->h_addr_list, p_he->h_length ); }
2466   return size;
2467 }
2468
2469 int WS_dup_he(LPWSINFO pwsi, struct hostent* p_he, int flag)
2470 {
2471    /* Convert hostent structure into ws_hostent so that the data fits 
2472     * into pwsi->buffer. Internal pointers can be linear, SEGPTR, or 
2473     * relative to pwsi->buffer depending on "flag" value. Returns size
2474     * of the data copied (also in the pwsi->buflen).
2475     */
2476
2477    int size = hostent_size(p_he);
2478
2479    if( size )
2480    {
2481      struct ws_hostent* p_to;
2482      char* p_name,*p_aliases,*p_addr,*p_base,*p;
2483
2484      _check_buffer_he(pwsi, size);
2485      p_to = (struct ws_hostent*)pwsi->he;
2486      p = (char*)pwsi->he;
2487      p_base = (flag & WS_DUP_OFFSET) ? NULL
2488                                      : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p);
2489      p += sizeof(struct ws_hostent);
2490      p_name = p;
2491      strcpy(p, p_he->h_name); p += strlen(p) + 1;
2492      p_aliases = p;
2493      p += list_dup(p_he->h_aliases, p, p_base + (p - (char*)pwsi->he), 0);
2494      p_addr = p;
2495      list_dup(p_he->h_addr_list, p, p_base + (p - (char*)pwsi->he), p_he->h_length);
2496
2497      p_to->h_addrtype = (INT16)p_he->h_addrtype; 
2498      p_to->h_length = (INT16)p_he->h_length;
2499      p_to->h_name = (SEGPTR)(p_base + (p_name - (char*)pwsi->he));
2500      p_to->h_aliases = (SEGPTR)(p_base + (p_aliases - (char*)pwsi->he));
2501      p_to->h_addr_list = (SEGPTR)(p_base + (p_addr - (char*)pwsi->he));
2502
2503      size += (sizeof(struct ws_hostent) - sizeof(struct hostent));
2504    }
2505    return size;
2506 }
2507
2508 /* ----- protoent */
2509
2510 static int protoent_size(struct protoent* p_pe)
2511 {
2512   int size = 0;
2513   if( p_pe )
2514   { size  = sizeof(struct protoent);
2515     size += strlen(p_pe->p_name) + 1;
2516     size += list_size(p_pe->p_aliases, 0); }
2517   return size;
2518 }
2519
2520 int WS_dup_pe(LPWSINFO pwsi, struct protoent* p_pe, int flag)
2521 {
2522    int size = protoent_size(p_pe);
2523    if( size )
2524    {
2525      struct ws_protoent* p_to;
2526      char* p_name,*p_aliases,*p_base,*p;
2527
2528      _check_buffer_pe(pwsi, size);
2529      p_to = (struct ws_protoent*)pwsi->pe;
2530      p = (char*)pwsi->pe; 
2531      p_base = (flag & WS_DUP_OFFSET) ? NULL
2532                                      : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p);
2533      p += sizeof(struct ws_protoent);
2534      p_name = p;
2535      strcpy(p, p_pe->p_name); p += strlen(p) + 1;
2536      p_aliases = p;
2537      list_dup(p_pe->p_aliases, p, p_base + (p - (char*)pwsi->pe), 0);
2538
2539      p_to->p_proto = (INT16)p_pe->p_proto;
2540      p_to->p_name = (SEGPTR)(p_base) + (p_name - (char*)pwsi->pe);
2541      p_to->p_aliases = (SEGPTR)((p_base) + (p_aliases - (char*)pwsi->pe)); 
2542
2543      size += (sizeof(struct ws_protoent) - sizeof(struct protoent));
2544    }
2545    return size;
2546 }
2547
2548 /* ----- servent */
2549
2550 static int servent_size(struct servent* p_se)
2551 {
2552   int size = 0;
2553   if( p_se )
2554   { size += sizeof(struct servent);
2555     size += strlen(p_se->s_proto) + strlen(p_se->s_name) + 2;
2556     size += list_size(p_se->s_aliases, 0); }
2557   return size;
2558 }
2559
2560 int WS_dup_se(LPWSINFO pwsi, struct servent* p_se, int flag)
2561 {
2562    int size = servent_size(p_se);
2563    if( size )
2564    {
2565      struct ws_servent* p_to;
2566      char* p_name,*p_aliases,*p_proto,*p_base,*p;
2567
2568      _check_buffer_se(pwsi, size);
2569      p_to = (struct ws_servent*)pwsi->se;
2570      p = (char*)pwsi->se;
2571      p_base = (flag & WS_DUP_OFFSET) ? NULL 
2572                                      : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p);
2573      p += sizeof(struct ws_servent);
2574      p_name = p;
2575      strcpy(p, p_se->s_name); p += strlen(p) + 1;
2576      p_proto = p;
2577      strcpy(p, p_se->s_proto); p += strlen(p) + 1;
2578      p_aliases = p;
2579      list_dup(p_se->s_aliases, p, p_base + (p - (char*)pwsi->se), 0);
2580
2581      p_to->s_port = (INT16)p_se->s_port;
2582      p_to->s_name = (SEGPTR)(p_base + (p_name - (char*)pwsi->se));
2583      p_to->s_proto = (SEGPTR)(p_base + (p_proto - (char*)pwsi->se));
2584      p_to->s_aliases = (SEGPTR)(p_base + (p_aliases - (char*)pwsi->se)); 
2585
2586      size += (sizeof(struct ws_servent) - sizeof(struct servent));
2587    }
2588    return size;
2589 }
2590
2591 /* ----------------------------------- error handling */
2592
2593 UINT16 wsaErrno(void)
2594 {
2595     int loc_errno = errno; 
2596 #ifdef HAVE_STRERROR
2597     WARN(winsock, "errno %d, (%s).\n", loc_errno, strerror(loc_errno));
2598 #else
2599     WARN(winsock, "errno %d\n", loc_errno);
2600 #endif
2601
2602     switch(loc_errno)
2603     {
2604         case EINTR:             return WSAEINTR;
2605         case EBADF:             return WSAEBADF;
2606         case EACCES:            return WSAEACCES;
2607         case EFAULT:            return WSAEFAULT;
2608         case EINVAL:            return WSAEINVAL;
2609         case EMFILE:            return WSAEMFILE;
2610         case EWOULDBLOCK:       return WSAEWOULDBLOCK;
2611         case EINPROGRESS:       return WSAEINPROGRESS;
2612         case EALREADY:          return WSAEALREADY;
2613         case ENOTSOCK:          return WSAENOTSOCK;
2614         case EDESTADDRREQ:      return WSAEDESTADDRREQ;
2615         case EMSGSIZE:          return WSAEMSGSIZE;
2616         case EPROTOTYPE:        return WSAEPROTOTYPE;
2617         case ENOPROTOOPT:       return WSAENOPROTOOPT;
2618         case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
2619         case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
2620         case EOPNOTSUPP:        return WSAEOPNOTSUPP;
2621         case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
2622         case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
2623         case EADDRINUSE:        return WSAEADDRINUSE;
2624         case EADDRNOTAVAIL:     return WSAEADDRNOTAVAIL;
2625         case ENETDOWN:          return WSAENETDOWN;
2626         case ENETUNREACH:       return WSAENETUNREACH;
2627         case ENETRESET:         return WSAENETRESET;
2628         case ECONNABORTED:      return WSAECONNABORTED;
2629         case EPIPE:
2630         case ECONNRESET:        return WSAECONNRESET;
2631         case ENOBUFS:           return WSAENOBUFS;
2632         case EISCONN:           return WSAEISCONN;
2633         case ENOTCONN:          return WSAENOTCONN;
2634         case ESHUTDOWN:         return WSAESHUTDOWN;
2635         case ETOOMANYREFS:      return WSAETOOMANYREFS;
2636         case ETIMEDOUT:         return WSAETIMEDOUT;
2637         case ECONNREFUSED:      return WSAECONNREFUSED;
2638         case ELOOP:             return WSAELOOP;
2639         case ENAMETOOLONG:      return WSAENAMETOOLONG;
2640         case EHOSTDOWN:         return WSAEHOSTDOWN;
2641         case EHOSTUNREACH:      return WSAEHOSTUNREACH;
2642         case ENOTEMPTY:         return WSAENOTEMPTY;
2643 #ifdef EPROCLIM
2644         case EPROCLIM:          return WSAEPROCLIM;
2645 #endif
2646 #ifdef EUSERS
2647         case EUSERS:            return WSAEUSERS;
2648 #endif
2649 #ifdef EDQUOT
2650         case EDQUOT:            return WSAEDQUOT;
2651 #endif
2652 #ifdef ESTALE
2653         case ESTALE:            return WSAESTALE;
2654 #endif
2655 #ifdef EREMOTE
2656         case EREMOTE:           return WSAEREMOTE;
2657 #endif
2658
2659        /* just in case we ever get here and there are no problems */
2660         case 0:                 return 0;
2661         default:
2662                 WARN(winsock, "Unknown errno %d!\n", loc_errno);
2663                 return WSAEOPNOTSUPP;
2664     }
2665 }
2666
2667 UINT16 wsaHerrno(void)
2668 {
2669     int         loc_errno = h_errno;
2670
2671     WARN(winsock, "h_errno %d.\n", loc_errno);
2672
2673     switch(loc_errno)
2674     {
2675         case HOST_NOT_FOUND:    return WSAHOST_NOT_FOUND;
2676         case TRY_AGAIN:         return WSATRY_AGAIN;
2677         case NO_RECOVERY:       return WSANO_RECOVERY;
2678         case NO_DATA:           return WSANO_DATA; 
2679
2680         case 0:                 return 0;
2681         default:
2682                 WARN(winsock,"Unknown h_errno %d!\n", loc_errno);
2683                 return WSAEOPNOTSUPP;
2684     }
2685 }