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