|  | /* | 
|  | * based on Windows Sockets 1.1 specs | 
|  | * (ftp.microsoft.com:/Advsys/winsock/spec11/WINSOCK.TXT) | 
|  | * | 
|  | * (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka. | 
|  | * | 
|  | * NOTE: If you make any changes to fix a particular app, make sure | 
|  | * they don't break something else like Netscape or telnet and ftp | 
|  | * clients and servers (www.winsite.com got a lot of those). | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #include <string.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/ipc.h> | 
|  | #include <sys/ioctl.h> | 
|  | #ifdef HAVE_SYS_FILIO_H | 
|  | # include <sys/filio.h> | 
|  | #endif | 
|  | #if defined(__svr4__) | 
|  | #include <sys/ioccom.h> | 
|  | #include <sys/sockio.h> | 
|  | #endif | 
|  |  | 
|  | #if defined(__EMX__) | 
|  | # include <sys/so_ioctl.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef HAVE_SYS_PARAM_H | 
|  | # include <sys/param.h> | 
|  | #endif | 
|  |  | 
|  | #include <sys/msg.h> | 
|  | #include <sys/wait.h> | 
|  | #include <sys/socket.h> | 
|  | #include <netinet/in.h> | 
|  | #include <arpa/inet.h> | 
|  | #include <ctype.h> | 
|  | #include <fcntl.h> | 
|  | #include <errno.h> | 
|  | #include <sys/errno.h> | 
|  | #include <netdb.h> | 
|  | #include <unistd.h> | 
|  | #include <stdlib.h> | 
|  | #ifdef HAVE_ARPA_NAMESER_H | 
|  | # include <arpa/nameser.h> | 
|  | #endif | 
|  | #ifdef HAVE_RESOLV_H | 
|  | # include <resolv.h> | 
|  | #endif | 
|  |  | 
|  | #include "wine/winbase16.h" | 
|  | #include "winsock.h" | 
|  | #include "winnt.h" | 
|  | #include "heap.h" | 
|  | #include "task.h" | 
|  | #include "message.h" | 
|  | #include "miscemu.h" | 
|  | #include "debug.h" | 
|  |  | 
|  | #define DEBUG_SOCKADDR 0 | 
|  | #define dump_sockaddr(a) \ | 
|  | DUMP("sockaddr_in: family %d, address %s, port %d\n", \ | 
|  | ((struct sockaddr_in *)a)->sin_family, \ | 
|  | inet_ntoa(((struct sockaddr_in *)a)->sin_addr), \ | 
|  | ntohs(((struct sockaddr_in *)a)->sin_port)) | 
|  |  | 
|  | #pragma pack(4) | 
|  |  | 
|  | /* ----------------------------------- internal data */ | 
|  |  | 
|  | static HANDLE 	_WSHeap = 0; | 
|  | static unsigned char*	_ws_stub = NULL; | 
|  | static LPWSINFO         _wsi_list = NULL; | 
|  |  | 
|  | #define WS_ALLOC(size) \ | 
|  | HeapAlloc(_WSHeap, HEAP_ZERO_MEMORY, (size) ) | 
|  | #define WS_FREE(ptr) \ | 
|  | HeapFree(_WSHeap, 0, (ptr) ) | 
|  |  | 
|  | #define WS_PTR2HANDLE(ptr) \ | 
|  | ((short)((int)(ptr) - (int)_ws_stub)) | 
|  | #define WS_HANDLE2PTR(handle) \ | 
|  | ((unsigned)((int)_ws_stub + (int)(handle))) | 
|  |  | 
|  | #define WSI_CHECK_RANGE(pwsi, pws) \ | 
|  | ( ((unsigned)(pws) > (unsigned)(pwsi)) && \ | 
|  | ((unsigned)(pws) < ((unsigned)(pwsi) + sizeof(WSINFO))) ) | 
|  |  | 
|  | static INT         _ws_sock_ops[] = | 
|  | { WS_SO_DEBUG, WS_SO_REUSEADDR, WS_SO_KEEPALIVE, WS_SO_DONTROUTE, | 
|  | WS_SO_BROADCAST, WS_SO_LINGER, WS_SO_OOBINLINE, WS_SO_SNDBUF, | 
|  | WS_SO_RCVBUF, WS_SO_ERROR, WS_SO_TYPE, WS_SO_DONTLINGER, 0 }; | 
|  | static int           _px_sock_ops[] = | 
|  | { SO_DEBUG, SO_REUSEADDR, SO_KEEPALIVE, SO_DONTROUTE, SO_BROADCAST, | 
|  | SO_LINGER, SO_OOBINLINE, SO_SNDBUF, SO_RCVBUF, SO_ERROR, SO_TYPE, | 
|  | SO_LINGER }; | 
|  |  | 
|  |  | 
|  | static INT _ws_tcp_ops[] = { | 
|  | #ifdef TCP_NODELAY | 
|  | WS_TCP_NODELAY, | 
|  | #endif | 
|  | 0 | 
|  | }; | 
|  | static int _px_tcp_ops[] = { | 
|  | #ifdef TCP_NODELAY | 
|  | TCP_NODELAY, | 
|  | #endif | 
|  | 0 | 
|  | }; | 
|  |  | 
|  | static int   _check_ws(LPWSINFO pwsi, ws_socket* pws); | 
|  | static char* _check_buffer(LPWSINFO pwsi, int size); | 
|  |  | 
|  | /*********************************************************************** | 
|  | *          convert_sockopt() | 
|  | * | 
|  | * Converts socket flags from Windows format. | 
|  | */ | 
|  | static void convert_sockopt(INT *level, INT *optname) | 
|  | { | 
|  | int i; | 
|  | switch (*level) | 
|  | { | 
|  | case WS_SOL_SOCKET: | 
|  | *level = SOL_SOCKET; | 
|  | for(i=0; _ws_sock_ops[i]; i++) | 
|  | if( _ws_sock_ops[i] == *optname ) break; | 
|  | if( _ws_sock_ops[i] ) *optname = _px_sock_ops[i]; | 
|  | else FIXME(winsock, "Unknown SOL_SOCKET optname %d\n", *optname); | 
|  | break; | 
|  | case WS_IPPROTO_TCP: | 
|  | *level = IPPROTO_TCP; | 
|  | for(i=0; _ws_tcp_ops[i]; i++) | 
|  | if ( _ws_tcp_ops[i] == *optname ) break; | 
|  | if( _ws_tcp_ops[i] ) *optname = _px_tcp_ops[i]; | 
|  | else FIXME(winsock, "Unknown IPPROTO_TCP optname %d\n", *optname); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* ----------------------------------- Per-thread info (or per-process?) */ | 
|  |  | 
|  | static LPWSINFO wsi_find(HTASK16 hTask) | 
|  | { | 
|  | TDB*	   pTask = (TDB*)GlobalLock16(hTask); | 
|  | if( pTask ) | 
|  | { | 
|  | if( pTask->pwsi ) return pTask->pwsi; | 
|  | else | 
|  | { | 
|  | LPWSINFO pwsi = _wsi_list; | 
|  | while( pwsi && pwsi->tid != hTask ) pwsi = pwsi->next; | 
|  | if( pwsi ) | 
|  | WARN(winsock,"(pwsi=0x%08x,task=0x%04x):Loose wsi struct! \n", | 
|  | (unsigned)pwsi, hTask ); | 
|  | return pwsi; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static ws_socket* wsi_alloc_socket(LPWSINFO pwsi, int fd) | 
|  | { | 
|  | /* Initialize a new entry in the socket table */ | 
|  |  | 
|  | if( pwsi->last_free >= 0 ) | 
|  | { | 
|  | int i = pwsi->last_free; | 
|  |  | 
|  | pwsi->last_free = pwsi->sock[i].flags;	/* free list */ | 
|  | pwsi->sock[i].fd = fd; | 
|  | pwsi->sock[i].flags = 0; | 
|  | return &pwsi->sock[i]; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static int wsi_strtolo(LPWSINFO pwsi, const char* name, const char* opt) | 
|  | { | 
|  | /* Stuff a lowercase copy of the string into the local buffer */ | 
|  |  | 
|  | int i = strlen(name) + 2; | 
|  | char* p = _check_buffer(pwsi, i + ((opt)?strlen(opt):0)); | 
|  |  | 
|  | if( p ) | 
|  | { | 
|  | do *p++ = tolower(*name); while(*name++); | 
|  | i = (p - (char*)(pwsi->buffer)); | 
|  | if( opt ) do *p++ = tolower(*opt); while(*opt++); | 
|  | return i; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static fd_set* fd_set_import( fd_set* fds, LPWSINFO pwsi, void* wsfds, int* highfd, BOOL b32 ) | 
|  | { | 
|  | /* translate Winsock fd set into local fd set */ | 
|  |  | 
|  | if( wsfds ) | 
|  | { | 
|  | #define wsfds16	((ws_fd_set16*)wsfds) | 
|  | #define wsfds32 ((ws_fd_set32*)wsfds) | 
|  | ws_socket* pws; | 
|  | int i, count; | 
|  |  | 
|  | FD_ZERO(fds); | 
|  | count = b32 ? wsfds32->fd_count : wsfds16->fd_count; | 
|  |  | 
|  | for( i = 0; i < count; i++ ) | 
|  | { | 
|  | pws = (b32) ? (ws_socket*)WS_HANDLE2PTR(wsfds32->fd_array[i]) | 
|  | : (ws_socket*)WS_HANDLE2PTR(wsfds16->fd_array[i]); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | if( pws->fd > *highfd ) *highfd = pws->fd; | 
|  | FD_SET(pws->fd, fds); | 
|  | } | 
|  | } | 
|  | #undef wsfds32 | 
|  | #undef wsfds16 | 
|  | return fds; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | __inline__ static int sock_error_p(int s) | 
|  | { | 
|  | unsigned int optval, optlen; | 
|  |  | 
|  | optlen = sizeof(optval); | 
|  | getsockopt(s, SOL_SOCKET, SO_ERROR, &optval, &optlen); | 
|  | if (optval) WARN(winsock, "\t[%i] error: %d\n", s, optval); | 
|  | return optval != 0; | 
|  | } | 
|  |  | 
|  | static int fd_set_export( LPWSINFO pwsi, fd_set* fds, fd_set* exceptfds, void* wsfds, BOOL b32 ) | 
|  | { | 
|  | int num_err = 0; | 
|  |  | 
|  | /* translate local fd set into Winsock fd set, adding | 
|  | * errors to exceptfds (only if app requested it) */ | 
|  |  | 
|  | if( wsfds ) | 
|  | { | 
|  | #define wsfds16 ((ws_fd_set16*)wsfds) | 
|  | #define wsfds32 ((ws_fd_set32*)wsfds) | 
|  | int i, j, count = (b32) ? wsfds32->fd_count : wsfds16->fd_count; | 
|  |  | 
|  | for( i = 0, j = 0; i < count; i++ ) | 
|  | { | 
|  | ws_socket *pws = (b32) ? (ws_socket*)WS_HANDLE2PTR(wsfds32->fd_array[i]) | 
|  | : (ws_socket*)WS_HANDLE2PTR(wsfds16->fd_array[i]); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | int fd = pws->fd; | 
|  |  | 
|  | if( FD_ISSET(fd, fds) ) | 
|  | { | 
|  | if ( exceptfds && sock_error_p(fd) ) | 
|  | { | 
|  | FD_SET(fd, exceptfds); | 
|  | num_err++; | 
|  | } | 
|  | else if( b32 ) | 
|  | wsfds32->fd_array[j++] = wsfds32->fd_array[i]; | 
|  | else | 
|  | wsfds16->fd_array[j++] = wsfds16->fd_array[i]; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if( b32 ) wsfds32->fd_count = j; | 
|  | else wsfds16->fd_count = j; | 
|  |  | 
|  | TRACE(winsock, "\n"); | 
|  | #undef wsfds32 | 
|  | #undef wsfds16 | 
|  | } | 
|  | return num_err; | 
|  | } | 
|  |  | 
|  | HANDLE16 __ws_gethandle( void* ptr ) | 
|  | { | 
|  | return (HANDLE16)WS_PTR2HANDLE(ptr); | 
|  | } | 
|  |  | 
|  | void* __ws_memalloc( int size ) | 
|  | { | 
|  | return WS_ALLOC(size); | 
|  | } | 
|  |  | 
|  | void __ws_memfree(void* ptr) | 
|  | { | 
|  | WS_FREE(ptr); | 
|  | } | 
|  |  | 
|  | /* ----------------------------------- API ----- | 
|  | * | 
|  | * Init / cleanup / error checking. | 
|  | */ | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAStartup16()			(WINSOCK.115) | 
|  | * | 
|  | * Create socket control struct, attach it to the global list and | 
|  | * update a pointer in the task struct. | 
|  | */ | 
|  | INT16 WINAPI WSAStartup16(UINT16 wVersionRequested, LPWSADATA lpWSAData) | 
|  | { | 
|  | WSADATA WINSOCK_data = { 0x0101, 0x0101, | 
|  | "WINE Sockets 1.1", | 
|  | #ifdef linux | 
|  | "Linux/i386", | 
|  | #elif defined(__NetBSD__) | 
|  | "NetBSD/i386", | 
|  | #elif defined(sunos) | 
|  | "SunOS", | 
|  | #elif defined(__FreeBSD__) | 
|  | "FreeBSD", | 
|  | #elif defined(__OpenBSD__) | 
|  | "OpenBSD/i386", | 
|  | #else | 
|  | "Unknown", | 
|  | #endif | 
|  | WS_MAX_SOCKETS_PER_PROCESS, | 
|  | WS_MAX_UDP_DATAGRAM, (SEGPTR)NULL }; | 
|  | HTASK16             tid = GetCurrentTask(); | 
|  | LPWSINFO            pwsi; | 
|  |  | 
|  | TRACE(winsock, "verReq=%x\n", wVersionRequested); | 
|  |  | 
|  | if (LOBYTE(wVersionRequested) < 1 || (LOBYTE(wVersionRequested) == 1 && | 
|  | HIBYTE(wVersionRequested) < 1)) return WSAVERNOTSUPPORTED; | 
|  |  | 
|  | if (!lpWSAData) return WSAEINVAL; | 
|  |  | 
|  | /* initialize socket heap */ | 
|  |  | 
|  | if( !_ws_stub ) | 
|  | { | 
|  | _WSHeap = HeapCreate(HEAP_ZERO_MEMORY, 8120, 32768); | 
|  | if( !(_ws_stub = WS_ALLOC(0x10)) ) | 
|  | { | 
|  | ERR(winsock,"Fatal: failed to create WinSock heap\n"); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | if( _WSHeap == 0 ) return WSASYSNOTREADY; | 
|  |  | 
|  | /* create socket array for this task */ | 
|  |  | 
|  | pwsi = wsi_find(GetCurrentTask()); | 
|  | if( pwsi == NULL ) | 
|  | { | 
|  | TDB* pTask = (TDB*)GlobalLock16( tid ); | 
|  |  | 
|  | if( (pwsi = (LPWSINFO)WS_ALLOC( sizeof(WSINFO))) ) | 
|  | { | 
|  | int i = 0; | 
|  | pwsi->tid = tid; | 
|  | for( i = 0; i < WS_MAX_SOCKETS_PER_PROCESS; i++ ) | 
|  | { | 
|  | pwsi->sock[i].fd = -1; | 
|  | pwsi->sock[i].flags = i + 1; | 
|  | } | 
|  | pwsi->sock[WS_MAX_SOCKETS_PER_PROCESS - 1].flags = -1; | 
|  | } | 
|  | else return WSASYSNOTREADY; | 
|  |  | 
|  | /* add this control struct to the global list */ | 
|  |  | 
|  | pwsi->prev = NULL; | 
|  | if( _wsi_list ) | 
|  | _wsi_list->prev = pwsi; | 
|  | pwsi->next = _wsi_list; | 
|  | _wsi_list = pwsi; | 
|  | pTask->pwsi = pwsi; | 
|  | } | 
|  | else pwsi->num_startup++; | 
|  |  | 
|  | /* return winsock information */ | 
|  |  | 
|  | memcpy(lpWSAData, &WINSOCK_data, sizeof(WINSOCK_data)); | 
|  |  | 
|  | TRACE(winsock, "succeeded\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAStartup32()			(WSOCK32.115) | 
|  | */ | 
|  | INT WINAPI WSAStartup(UINT wVersionRequested, LPWSADATA lpWSAData) | 
|  | { | 
|  | return WSAStartup16( wVersionRequested, lpWSAData ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSACleanup()			(WINSOCK.116) | 
|  | * | 
|  | * Cleanup functions of varying impact. | 
|  | */ | 
|  | void WINSOCK_Shutdown() | 
|  | { | 
|  | /* Called on exit(), has to remove all outstanding async DNS processes.  */ | 
|  |  | 
|  | WINSOCK_cancel_task_aops( 0, __ws_memfree ); | 
|  | } | 
|  |  | 
|  | INT WINSOCK_DeleteTaskWSI( TDB* pTask, LPWSINFO pwsi ) | 
|  | { | 
|  | /* WSACleanup() backend, called on task termination as well. | 
|  | * Real DLL would have registered its own signal handler with | 
|  | * TaskSetSignalHandler() and waited until USIG_TERMINATION/USIG_GPF | 
|  | * but this scheme is much more straightforward. | 
|  | */ | 
|  |  | 
|  | int	i, j, n; | 
|  |  | 
|  | if( --pwsi->num_startup > 0 ) return 0; | 
|  |  | 
|  | SIGNAL_MaskAsyncEvents( TRUE ); | 
|  | WINSOCK_cancel_task_aops( pTask->hSelf, __ws_memfree ); | 
|  | SIGNAL_MaskAsyncEvents( FALSE ); | 
|  |  | 
|  | /* unlink socket control struct */ | 
|  |  | 
|  | if( pwsi == _wsi_list ) | 
|  | _wsi_list = pwsi->next; | 
|  | else | 
|  | pwsi->prev->next = pwsi->next; | 
|  | if( pwsi->next ) pwsi->next->prev = pwsi->prev; | 
|  |  | 
|  | if( _wsi_list == NULL ) | 
|  | WINSOCK_Shutdown();	/* just in case */ | 
|  |  | 
|  | if( pwsi->flags & WSI_BLOCKINGCALL ) | 
|  | TRACE(winsock,"\tinside blocking call!\n"); | 
|  |  | 
|  | /* FIXME: aop_control() doesn't decrement pwsi->num_async_rq | 
|  | * | 
|  | *    if( pwsi->num_async_rq ) | 
|  | *	  WARN(winsock,"\thave %i outstanding async ops!\n", pwsi->num_async_rq ); | 
|  | */ | 
|  |  | 
|  | for(i = 0, j = 0, n = 0; i < WS_MAX_SOCKETS_PER_PROCESS; i++) | 
|  | if( pwsi->sock[i].fd != -1 ) | 
|  | { | 
|  | if( pwsi->sock[i].psop ) | 
|  | { | 
|  | n++; | 
|  | WSAAsyncSelect( (SOCKET16)WS_PTR2HANDLE(pwsi->sock + i), 0, 0, 0 ); | 
|  | } | 
|  | close(pwsi->sock[i].fd); j++; | 
|  | } | 
|  | if( j ) | 
|  | TRACE(winsock,"\tclosed %i sockets, killed %i async selects!\n", j, n); | 
|  |  | 
|  | /* delete scratch buffers */ | 
|  |  | 
|  | if( pwsi->buffer ) SEGPTR_FREE(pwsi->buffer); | 
|  | if( pwsi->dbuffer ) SEGPTR_FREE(pwsi->dbuffer); | 
|  |  | 
|  | if( pTask ) | 
|  | pTask->pwsi = NULL; | 
|  | memset( pwsi, 0, sizeof(WSINFO) ); | 
|  | WS_FREE(pwsi); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | INT WINAPI WSACleanup(void) | 
|  | { | 
|  | HTASK16	hTask = GetCurrentTask(); | 
|  |  | 
|  | TRACE(winsock, "(%04x)\n", hTask ); | 
|  | if( hTask ) | 
|  | { | 
|  | LPWSINFO pwsi = wsi_find(hTask); | 
|  | if( pwsi ) | 
|  | return WINSOCK_DeleteTaskWSI( (TDB*)GlobalLock16(hTask), pwsi ); | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  | else | 
|  | WINSOCK_Shutdown(); /* remove all outstanding DNS requests */ | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAGetLastError()		(WSOCK32.111)(WINSOCK.111) | 
|  | */ | 
|  | INT WINAPI WSAGetLastError(void) | 
|  | { | 
|  | LPWSINFO pwsi = wsi_find(GetCurrentTask()); | 
|  | INT16    ret = (pwsi) ? pwsi->err : WSANOTINITIALISED; | 
|  |  | 
|  | TRACE(winsock, "(%08x) = %i\n", | 
|  | (unsigned)pwsi, (int)ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSASetLastError32()		(WSOCK32.112) | 
|  | */ | 
|  | void WINAPI WSASetLastError(INT iError) | 
|  | { | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): %d\n", (unsigned)pwsi, (int)iError); | 
|  | if( pwsi ) pwsi->err = iError; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSASetLastError16()		(WINSOCK.112) | 
|  | */ | 
|  | void WINAPI WSASetLastError16(INT16 iError) | 
|  | { | 
|  | WSASetLastError(iError); | 
|  | } | 
|  |  | 
|  | int _check_ws(LPWSINFO pwsi, ws_socket* pws) | 
|  | { | 
|  | if( pwsi ) | 
|  | { | 
|  | if( pwsi->flags & WSI_BLOCKINGCALL ) pwsi->err = WSAEINPROGRESS; | 
|  | else if( WSI_CHECK_RANGE(pwsi, pws) ) return 1; | 
|  | else pwsi->err = WSAENOTSOCK; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | char* _check_buffer(LPWSINFO pwsi, int size) | 
|  | { | 
|  | if( pwsi->buffer && pwsi->buflen >= size ) return pwsi->buffer; | 
|  | else SEGPTR_FREE(pwsi->buffer); | 
|  |  | 
|  | pwsi->buffer = (char*)SEGPTR_ALLOC((pwsi->buflen = size)); | 
|  | return pwsi->buffer; | 
|  | } | 
|  |  | 
|  | struct ws_hostent* _check_buffer_he(LPWSINFO pwsi, int size) | 
|  | { | 
|  | if( pwsi->he && pwsi->helen >= size ) return pwsi->he; | 
|  | else SEGPTR_FREE(pwsi->he); | 
|  |  | 
|  | pwsi->he = (struct ws_hostent*)SEGPTR_ALLOC((pwsi->helen = size)); | 
|  | return pwsi->he; | 
|  | } | 
|  |  | 
|  | struct ws_servent* _check_buffer_se(LPWSINFO pwsi, int size) | 
|  | { | 
|  | if( pwsi->se && pwsi->selen >= size ) return pwsi->se; | 
|  | else SEGPTR_FREE(pwsi->se); | 
|  |  | 
|  | pwsi->se = (struct ws_servent*)SEGPTR_ALLOC((pwsi->selen = size)); | 
|  | return pwsi->se; | 
|  | } | 
|  |  | 
|  | struct ws_protoent* _check_buffer_pe(LPWSINFO pwsi, int size) | 
|  | { | 
|  | if( pwsi->pe && pwsi->pelen >= size ) return pwsi->pe; | 
|  | else SEGPTR_FREE(pwsi->pe); | 
|  |  | 
|  | pwsi->pe = (struct ws_protoent*)SEGPTR_ALLOC((pwsi->pelen = size)); | 
|  | return pwsi->pe; | 
|  | } | 
|  |  | 
|  | /* ----------------------------------- i/o APIs */ | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		accept()		(WSOCK32.1) | 
|  | */ | 
|  | SOCKET WINAPI WINSOCK_accept(SOCKET s, struct sockaddr *addr, | 
|  | INT *addrlen32) | 
|  | { | 
|  | ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR((SOCKET16)s); | 
|  | LPWSINFO                 pwsi = wsi_find(GetCurrentTask()); | 
|  | #ifdef HAVE_IPX | 
|  | struct ws_sockaddr_ipx*  addr2 = (struct ws_sockaddr_ipx *)addr; | 
|  | #endif | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x\n", | 
|  | (unsigned)pwsi, (UINT16)s ); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | int 	sock, fd_flags; | 
|  |  | 
|  | fd_flags = fcntl(pws->fd, F_GETFL, 0); | 
|  |  | 
|  | if( (sock = accept(pws->fd, addr, addrlen32)) >= 0 ) | 
|  | { | 
|  | ws_socket*	pnew = wsi_alloc_socket(pwsi, sock); | 
|  | if( pnew ) | 
|  | { | 
|  | s = (SOCKET)WS_PTR2HANDLE(pnew); | 
|  | if( pws->psop && pws->flags & WS_FD_ACCEPT ) | 
|  | { | 
|  | EVENT_AddIO( pws->fd, EVENT_IO_READ );	/* reenabler */ | 
|  |  | 
|  | /* async select the accept()'ed socket */ | 
|  | WSAAsyncSelect( s, pws->psop->hWnd, pws->psop->uMsg, | 
|  | pws->flags & ~WS_FD_ACCEPT ); | 
|  | } | 
|  | #ifdef HAVE_IPX | 
|  | if (addr && ((struct sockaddr_ipx *)addr)->sipx_family == AF_IPX) { | 
|  | addr = (struct sockaddr *) | 
|  | malloc(addrlen32 ? *addrlen32 : sizeof(*addr2)); | 
|  | memcpy(addr, addr2, | 
|  | addrlen32 ? *addrlen32 : sizeof(*addr2)); | 
|  | addr2->sipx_family = WS_AF_IPX; | 
|  | addr2->sipx_network = ((struct sockaddr_ipx *)addr)->sipx_network; | 
|  | addr2->sipx_port = ((struct sockaddr_ipx *)addr)->sipx_port; | 
|  | memcpy(addr2->sipx_node, | 
|  | ((struct sockaddr_ipx *)addr)->sipx_node, IPX_NODE_LEN); | 
|  | free(addr); | 
|  | } | 
|  | #endif | 
|  | return s; | 
|  | } | 
|  | else pwsi->err = WSAENOBUFS; | 
|  | } | 
|  | else pwsi->err = wsaErrno(); | 
|  | } | 
|  | #ifdef HAVE_IPX | 
|  | if (addr && ((struct sockaddr_ipx *)addr)->sipx_family == AF_IPX) { | 
|  | addr = (struct sockaddr *) | 
|  | malloc(addrlen32 ? *addrlen32 : sizeof(*addr2)); | 
|  | memcpy(addr, addr2, addrlen32 ? *addrlen32 : sizeof(*addr2)); | 
|  | addr2->sipx_family = WS_AF_IPX; | 
|  | addr2->sipx_network = ((struct sockaddr_ipx *)addr)->sipx_network; | 
|  | addr2->sipx_port = ((struct sockaddr_ipx *)addr)->sipx_port; | 
|  | memcpy(addr2->sipx_node, | 
|  | ((struct sockaddr_ipx *)addr)->sipx_node, IPX_NODE_LEN); | 
|  | free(addr); | 
|  | } | 
|  | #endif | 
|  | return INVALID_SOCKET; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              accept()		(WINSOCK.1) | 
|  | */ | 
|  | SOCKET16 WINAPI WINSOCK_accept16(SOCKET16 s, struct sockaddr* addr, | 
|  | INT16* addrlen16 ) | 
|  | { | 
|  | INT addrlen32 = addrlen16 ? *addrlen16 : 0; | 
|  | SOCKET retSocket = WINSOCK_accept( s, addr, &addrlen32 ); | 
|  | if( addrlen16 ) *addrlen16 = (INT16)addrlen32; | 
|  | return (SOCKET16)retSocket; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		bind()			(WSOCK32.2) | 
|  | */ | 
|  | INT WINAPI WINSOCK_bind(SOCKET s, struct sockaddr *name, INT namelen) | 
|  | { | 
|  | ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO                 pwsi = wsi_find(GetCurrentTask()); | 
|  | #ifdef HAVE_IPX | 
|  | struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name; | 
|  | #endif | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x, ptr %8x, length %d\n", | 
|  | (unsigned)pwsi, s, (int) name, namelen); | 
|  | #if DEBUG_SOCKADDR | 
|  | dump_sockaddr(name); | 
|  | #endif | 
|  |  | 
|  | if ( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | /* FIXME: what family does this really map to on the Unix side? */ | 
|  | if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_PUP) | 
|  | ((struct ws_sockaddr_ipx *)name)->sipx_family = AF_UNSPEC; | 
|  | #ifdef HAVE_IPX | 
|  | else if (name && | 
|  | ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_IPX) | 
|  | { | 
|  | name = (struct sockaddr *) malloc(sizeof(struct sockaddr_ipx)); | 
|  | memset(name, '\0', sizeof(struct sockaddr_ipx)); | 
|  | ((struct sockaddr_ipx *)name)->sipx_family = AF_IPX; | 
|  | ((struct sockaddr_ipx *)name)->sipx_port = name2->sipx_port; | 
|  | ((struct sockaddr_ipx *)name)->sipx_network = name2->sipx_network; | 
|  | memcpy(((struct sockaddr_ipx *)name)->sipx_node, | 
|  | name2->sipx_node, IPX_NODE_LEN); | 
|  | namelen = sizeof(struct sockaddr_ipx); | 
|  | } | 
|  | #endif | 
|  | if ( namelen >= sizeof(*name) ) | 
|  | { | 
|  | if ( name && (((struct ws_sockaddr_in *)name)->sin_family == AF_INET | 
|  | #ifdef HAVE_IPX | 
|  | || ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX | 
|  | #endif | 
|  | )) | 
|  | { | 
|  | if ( bind(pws->fd, name, namelen) < 0 ) | 
|  | { | 
|  | int	loc_errno = errno; | 
|  | WARN(winsock, "\tfailure - errno = %i\n", errno); | 
|  | errno = loc_errno; | 
|  | switch(errno) | 
|  | { | 
|  | case EBADF: pwsi->err = WSAENOTSOCK; break; | 
|  | case EADDRNOTAVAIL: pwsi->err = WSAEINVAL; break; | 
|  | default: pwsi->err = wsaErrno(); | 
|  | } | 
|  | } | 
|  | else { | 
|  | #ifdef HAVE_IPX | 
|  | if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX) | 
|  | free(name); | 
|  | #endif | 
|  | return 0; /* success */ | 
|  | } | 
|  | } | 
|  | else pwsi->err = WSAEAFNOSUPPORT; | 
|  | } | 
|  | else pwsi->err = WSAEFAULT; | 
|  | #ifdef HAVE_IPX | 
|  | if (name && ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX) | 
|  | free(name); | 
|  | #endif | 
|  | } | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              bind()			(WINSOCK.2) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_bind16(SOCKET16 s, struct sockaddr *name, INT16 namelen) | 
|  | { | 
|  | return (INT16)WINSOCK_bind( s, name, namelen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		closesocket()		(WSOCK32.3) | 
|  | */ | 
|  | INT WINAPI WINSOCK_closesocket(SOCKET s) | 
|  | { | 
|  | ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %08x\n", (unsigned)pwsi, s); | 
|  |  | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | int	fd = pws->fd; | 
|  |  | 
|  | if( pws->psop ) WSAAsyncSelect( s, 0, 0, 0 ); | 
|  |  | 
|  | pws->fd = -1; | 
|  | pws->flags = (unsigned)pwsi->last_free; | 
|  | pwsi->last_free = pws - &pwsi->sock[0]; /* add to free list */ | 
|  |  | 
|  | if( close(fd) == 0 ) | 
|  | return 0; | 
|  | pwsi->err = (errno == EBADF) ? WSAENOTSOCK : wsaErrno(); | 
|  | } | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              closesocket()           (WINSOCK.3) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_closesocket16(SOCKET16 s) | 
|  | { | 
|  | return (INT16)WINSOCK_closesocket(s); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		connect()		(WSOCK32.4) | 
|  | */ | 
|  | INT WINAPI WINSOCK_connect(SOCKET s, struct sockaddr *name, INT namelen) | 
|  | { | 
|  | ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO                 pwsi = wsi_find(GetCurrentTask()); | 
|  | #ifdef HAVE_IPX | 
|  | struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name; | 
|  | #endif | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x, ptr %8x, length %d\n", | 
|  | (unsigned)pwsi, s, (int) name, namelen); | 
|  | #if DEBUG_SOCKADDR | 
|  | dump_sockaddr(name); | 
|  | #endif | 
|  |  | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_PUP) | 
|  | ((struct ws_sockaddr_ipx *)name)->sipx_family = AF_UNSPEC; | 
|  | #ifdef HAVE_IPX | 
|  | else if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_IPX) | 
|  | { | 
|  | name = (struct sockaddr *) malloc(sizeof(struct sockaddr_ipx)); | 
|  | memset(name, '\0', sizeof(struct sockaddr_ipx)); | 
|  | ((struct sockaddr_ipx *)name)->sipx_family = AF_IPX; | 
|  | ((struct sockaddr_ipx *)name)->sipx_port = name2->sipx_port; | 
|  | ((struct sockaddr_ipx *)name)->sipx_network = name2->sipx_network; | 
|  | memcpy(((struct sockaddr_ipx *)name)->sipx_node, | 
|  | name2->sipx_node, IPX_NODE_LEN); | 
|  | namelen = sizeof(struct sockaddr_ipx); | 
|  | } | 
|  | #endif | 
|  | if (connect(pws->fd, name, namelen) == 0) | 
|  | { | 
|  | if( pws->psop && (pws->flags & WS_FD_CONNECT) ) | 
|  | { | 
|  | /* application did AsyncSelect() but then went | 
|  | * ahead and called connect() without waiting for | 
|  | * notification. | 
|  | * | 
|  | * FIXME: Do we have to post a notification message | 
|  | *        in this case? | 
|  | */ | 
|  |  | 
|  | if( !(pws->flags & WS_FD_CONNECTED) ) | 
|  | { | 
|  | if( pws->flags & (WS_FD_READ | WS_FD_CLOSE) ) | 
|  | EVENT_AddIO( pws->fd, EVENT_IO_READ ); | 
|  | else | 
|  | EVENT_DeleteIO( pws->fd, EVENT_IO_READ ); | 
|  | if( pws->flags & WS_FD_WRITE ) | 
|  | EVENT_AddIO( pws->fd, EVENT_IO_WRITE ); | 
|  | else | 
|  | EVENT_DeleteIO( pws->fd, EVENT_IO_WRITE ); | 
|  | } | 
|  | } | 
|  | pws->flags |= WS_FD_CONNECTED; | 
|  | pws->flags &= ~(WS_FD_INACTIVE | WS_FD_CONNECT | WS_FD_LISTENING); | 
|  | #ifdef HAVE_IPX | 
|  | if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX) | 
|  | free(name); | 
|  | #endif | 
|  | return 0; | 
|  | } | 
|  | pwsi->err = (errno == EINPROGRESS) ? WSAEWOULDBLOCK : wsaErrno(); | 
|  | } | 
|  | #ifdef HAVE_IPX | 
|  | if (name && ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX) | 
|  | free(name); | 
|  | #endif | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              connect()               (WINSOCK.4) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_connect16(SOCKET16 s, struct sockaddr *name, INT16 namelen) | 
|  | { | 
|  | return (INT16)WINSOCK_connect( s, name, namelen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getpeername()		(WSOCK32.5) | 
|  | */ | 
|  | INT WINAPI WINSOCK_getpeername(SOCKET s, struct sockaddr *name, | 
|  | INT *namelen) | 
|  | { | 
|  | ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO                 pwsi = wsi_find(GetCurrentTask()); | 
|  | #ifdef HAVE_IPX | 
|  | struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name; | 
|  | #endif | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket: %04x, ptr %8x, ptr %8x\n", | 
|  | (unsigned)pwsi, s, (int) name, *namelen); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | if (getpeername(pws->fd, name, namelen) == 0) { | 
|  | #ifdef HAVE_IPX | 
|  | if (((struct ws_sockaddr_ipx *)name)->sipx_family == AF_IPX) { | 
|  | name = (struct sockaddr *) | 
|  | malloc(namelen ? *namelen : sizeof(*name2)); | 
|  | memcpy(name, name2, namelen ? *namelen : sizeof(*name2)); | 
|  | name2->sipx_family = WS_AF_IPX; | 
|  | name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network; | 
|  | name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port; | 
|  | memcpy(name2->sipx_node, | 
|  | ((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN); | 
|  | free(name); | 
|  | } | 
|  | #endif | 
|  | return 0; | 
|  | } | 
|  | pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); | 
|  | } | 
|  | #ifdef HAVE_IPX | 
|  | if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == AF_IPX) { | 
|  | name = (struct sockaddr *) malloc(namelen ? *namelen : sizeof(*name2)); | 
|  | memcpy(name, name2, namelen ? *namelen : sizeof(*name2)); | 
|  | name2->sipx_family = WS_AF_IPX; | 
|  | name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network; | 
|  | name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port; | 
|  | memcpy(name2->sipx_node, | 
|  | ((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN); | 
|  | free(name); | 
|  | } | 
|  | #endif | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              getpeername()		(WINSOCK.5) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_getpeername16(SOCKET16 s, struct sockaddr *name, | 
|  | INT16 *namelen16) | 
|  | { | 
|  | INT namelen32 = *namelen16; | 
|  | INT retVal = WINSOCK_getpeername( s, name, &namelen32 ); | 
|  |  | 
|  | #if DEBUG_SOCKADDR | 
|  | dump_sockaddr(name); | 
|  | #endif | 
|  |  | 
|  | *namelen16 = namelen32; | 
|  | return (INT16)retVal; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getsockname()		(WSOCK32.6) | 
|  | */ | 
|  | INT WINAPI WINSOCK_getsockname(SOCKET s, struct sockaddr *name, | 
|  | INT *namelen) | 
|  | { | 
|  | ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO                 pwsi = wsi_find(GetCurrentTask()); | 
|  | #ifdef HAVE_IPX | 
|  | struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name; | 
|  | #endif | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket: %04x, ptr %8x, ptr %8x\n", | 
|  | (unsigned)pwsi, s, (int) name, (int) *namelen); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | if (getsockname(pws->fd, name, namelen) == 0) { | 
|  | #ifdef HAVE_IPX | 
|  | if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX) { | 
|  | name = (struct sockaddr *) | 
|  | malloc(namelen ? *namelen : sizeof(*name2)); | 
|  | memcpy(name, name2, namelen ? *namelen : sizeof(*name2)); | 
|  | name2->sipx_family = WS_AF_IPX; | 
|  | name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network; | 
|  | name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port; | 
|  | memcpy(name2->sipx_node, | 
|  | ((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN); | 
|  | free(name); | 
|  | } | 
|  | #endif | 
|  | return 0; | 
|  | } | 
|  | pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); | 
|  | } | 
|  | #ifdef HAVE_IPX | 
|  | if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == AF_IPX) { | 
|  | name = (struct sockaddr *) malloc(namelen ? *namelen : sizeof(*name2)); | 
|  | memcpy(name, name2, namelen ? *namelen : sizeof(*name2)); | 
|  | name2->sipx_family = WS_AF_IPX; | 
|  | name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network; | 
|  | name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port; | 
|  | memcpy(name2->sipx_node, | 
|  | ((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN); | 
|  | free(name); | 
|  | } | 
|  | #endif | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              getsockname()		(WINSOCK.6) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_getsockname16(SOCKET16 s, struct sockaddr *name, | 
|  | INT16 *namelen16) | 
|  | { | 
|  | INT retVal; | 
|  |  | 
|  | if( namelen16 ) | 
|  | { | 
|  | INT namelen32 = *namelen16; | 
|  | retVal = WINSOCK_getsockname( s, name, &namelen32 ); | 
|  | *namelen16 = namelen32; | 
|  |  | 
|  | #if DEBUG_SOCKADDR | 
|  | dump_sockaddr(name); | 
|  | #endif | 
|  |  | 
|  | } | 
|  | else retVal = SOCKET_ERROR; | 
|  | return (INT16)retVal; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getsockopt()		(WSOCK32.7) | 
|  | */ | 
|  | INT WINAPI WINSOCK_getsockopt(SOCKET s, INT level, | 
|  | INT optname, char *optval, INT *optlen) | 
|  | { | 
|  | ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket: %04x, opt %d, ptr %8x, ptr %8x\n", | 
|  | (unsigned)pwsi, s, level, (int) optval, (int) *optlen); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | convert_sockopt(&level, &optname); | 
|  | if (getsockopt(pws->fd, (int) level, optname, optval, optlen) == 0 ) | 
|  | return 0; | 
|  | pwsi->err = (errno == EBADF) ? WSAENOTSOCK : wsaErrno(); | 
|  | } | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              getsockopt()		(WINSOCK.7) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_getsockopt16(SOCKET16 s, INT16 level, | 
|  | INT16 optname, char *optval, INT16 *optlen) | 
|  | { | 
|  | INT optlen32; | 
|  | INT *p = &optlen32; | 
|  | INT retVal; | 
|  | if( optlen ) optlen32 = *optlen; else p = NULL; | 
|  | retVal = WINSOCK_getsockopt( s, (UINT16)level, optname, optval, p ); | 
|  | if( optlen ) *optlen = optlen32; | 
|  | return (INT16)retVal; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		htonl()			(WINSOCK.8)(WSOCK32.8) | 
|  | */ | 
|  | u_long WINAPI WINSOCK_htonl(u_long hostlong)   { return( htonl(hostlong) ); } | 
|  | /*********************************************************************** | 
|  | *		htons()			(WINSOCK.9)(WSOCK32.9) | 
|  | */ | 
|  | u_short WINAPI WINSOCK_htons(u_short hostshort) { return( htons(hostshort) ); } | 
|  | /*********************************************************************** | 
|  | *		inet_addr()		(WINSOCK.10)(WSOCK32.10) | 
|  | */ | 
|  | u_long WINAPI WINSOCK_inet_addr(char *cp)      { return( inet_addr(cp) ); } | 
|  | /*********************************************************************** | 
|  | *		htohl()			(WINSOCK.14)(WSOCK32.14) | 
|  | */ | 
|  | u_long WINAPI WINSOCK_ntohl(u_long netlong)    { return( ntohl(netlong) ); } | 
|  | /*********************************************************************** | 
|  | *		ntohs()			(WINSOCK.15)(WSOCK32.15) | 
|  | */ | 
|  | u_short WINAPI WINSOCK_ntohs(u_short netshort)  { return( ntohs(netshort) ); } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		inet_ntoa()		(WINSOCK.11)(WSOCK32.11) | 
|  | */ | 
|  | char* WINAPI WINSOCK_inet_ntoa(struct in_addr in) | 
|  | { | 
|  | /* use "buffer for dummies" here because some applications have | 
|  | * propensity to decode addresses in ws_hostent structure without | 
|  | * saving them first... | 
|  | */ | 
|  |  | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | char*	s = inet_ntoa(in); | 
|  | if( s ) | 
|  | { | 
|  | if( pwsi->dbuffer == NULL ) | 
|  | if((pwsi->dbuffer = (char*) SEGPTR_ALLOC(32)) == NULL ) | 
|  | { | 
|  | pwsi->err = WSAENOBUFS; | 
|  | return NULL; | 
|  | } | 
|  | strncpy(pwsi->dbuffer, s, 32 ); | 
|  | return pwsi->dbuffer; | 
|  | } | 
|  | pwsi->err = wsaErrno(); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | SEGPTR WINAPI WINSOCK_inet_ntoa16(struct in_addr in) | 
|  | { | 
|  | char* retVal = WINSOCK_inet_ntoa(in); | 
|  | return retVal ? SEGPTR_GET(retVal) : (SEGPTR)NULL; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ioctlsocket()		(WSOCK32.12) | 
|  | */ | 
|  | INT WINAPI WINSOCK_ioctlsocket(SOCKET s, UINT cmd, UINT *argp) | 
|  | { | 
|  | ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x, cmd %08x, ptr %8x\n", | 
|  | (unsigned)pwsi, s, cmd, (unsigned) argp); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | long 	newcmd  = cmd; | 
|  |  | 
|  | switch( cmd ) | 
|  | { | 
|  | case WS_FIONREAD: | 
|  | newcmd=FIONREAD; | 
|  | break; | 
|  |  | 
|  | case WS_FIONBIO: | 
|  | newcmd=FIONBIO; | 
|  | if( pws->psop && *argp == 0 ) | 
|  | { | 
|  | /* AsyncSelect()'ed sockets are always nonblocking */ | 
|  | pwsi->err = WSAEINVAL; | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case WS_SIOCATMARK: | 
|  | newcmd=SIOCATMARK; | 
|  | break; | 
|  |  | 
|  | case WS_IOW('f',125,u_long): | 
|  | WARN(winsock,"Warning: WS1.1 shouldn't be using async I/O\n"); | 
|  | pwsi->err = WSAEINVAL; | 
|  | return SOCKET_ERROR; | 
|  |  | 
|  | default: | 
|  | /* Netscape tries hard to use bogus ioctl 0x667e */ | 
|  | WARN(winsock, "\tunknown WS_IOCTL cmd (%08x)\n", cmd); | 
|  | } | 
|  | if( ioctl(pws->fd, newcmd, (char*)argp ) == 0 ) return 0; | 
|  | pwsi->err = (errno == EBADF) ? WSAENOTSOCK : wsaErrno(); | 
|  | } | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              ioctlsocket()           (WINSOCK.12) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_ioctlsocket16(SOCKET16 s, UINT cmd, UINT *argp) | 
|  | { | 
|  | return (INT16)WINSOCK_ioctlsocket( s, cmd, argp ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		listen()		(WSOCK32.13) | 
|  | */ | 
|  | INT WINAPI WINSOCK_listen(SOCKET s, INT backlog) | 
|  | { | 
|  | ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x, backlog %d\n", | 
|  | (unsigned)pwsi, s, backlog); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | if (listen(pws->fd, backlog) == 0) | 
|  | { | 
|  | if( !pws->psop ) | 
|  | { | 
|  | int  fd_flags = fcntl(pws->fd, F_GETFL, 0); | 
|  | if( !(fd_flags & O_NONBLOCK) ) pws->flags |= WS_FD_ACCEPT; | 
|  | } | 
|  | pws->flags |= WS_FD_LISTENING; | 
|  | pws->flags &= ~(WS_FD_INACTIVE | WS_FD_CONNECT | WS_FD_CONNECTED); /* just in case */ | 
|  | return 0; | 
|  | } | 
|  | pwsi->err = wsaErrno(); | 
|  | } | 
|  | else if( pwsi ) pwsi->err = WSAENOTSOCK; | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              listen()		(WINSOCK.13) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_listen16(SOCKET16 s, INT16 backlog) | 
|  | { | 
|  | return (INT16)WINSOCK_listen( s, backlog ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		recv()			(WSOCK32.16) | 
|  | */ | 
|  | INT WINAPI WINSOCK_recv(SOCKET s, char *buf, INT len, INT flags) | 
|  | { | 
|  | ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x, buf %8x, len %d, " | 
|  | "flags %d\n", (unsigned)pwsi, s, (unsigned)buf, | 
|  | len, flags); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | INT length; | 
|  | if ((length = recv(pws->fd, buf, len, flags)) >= 0) | 
|  | { | 
|  | TRACE(winsock, " -> %i bytes\n", length); | 
|  |  | 
|  | if( pws->psop && (pws->flags & (WS_FD_READ | WS_FD_CLOSE)) ) | 
|  | EVENT_AddIO( pws->fd, EVENT_IO_READ );	/* reenabler */ | 
|  |  | 
|  | return length; | 
|  | } | 
|  | pwsi->err = wsaErrno(); | 
|  | } | 
|  | else if( pwsi ) pwsi->err = WSAENOTSOCK; | 
|  | WARN(winsock, " -> ERROR\n"); | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              recv()			(WINSOCK.16) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_recv16(SOCKET16 s, char *buf, INT16 len, INT16 flags) | 
|  | { | 
|  | return (INT16)WINSOCK_recv( s, buf, len, flags ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		recvfrom()		(WSOCK32.17) | 
|  | */ | 
|  | INT WINAPI WINSOCK_recvfrom(SOCKET s, char *buf, INT len, INT flags, | 
|  | struct sockaddr *from, INT *fromlen32) | 
|  | { | 
|  | ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO                 pwsi = wsi_find(GetCurrentTask()); | 
|  | #ifdef HAVE_IPX | 
|  | struct ws_sockaddr_ipx*  from2 = (struct ws_sockaddr_ipx *)from; | 
|  | #endif | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x, ptr %08x, " | 
|  | "len %d, flags %d\n", (unsigned)pwsi, s, (unsigned)buf, | 
|  | len, flags); | 
|  | #if DEBUG_SOCKADDR | 
|  | if( from ) dump_sockaddr(from); | 
|  | else DUMP("from = NULL\n"); | 
|  | #endif | 
|  |  | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | int length; | 
|  |  | 
|  | if ((length = recvfrom(pws->fd, buf, len, flags, from, fromlen32)) >= 0) | 
|  | { | 
|  | TRACE(winsock, " -> %i bytes\n", length); | 
|  |  | 
|  | if( pws->psop && (pws->flags & (WS_FD_READ | WS_FD_CLOSE)) ) | 
|  | EVENT_AddIO( pws->fd, EVENT_IO_READ );  /* reenabler */ | 
|  |  | 
|  | #ifdef HAVE_IPX | 
|  | if (from && ((struct sockaddr_ipx *)from)->sipx_family == AF_IPX) { | 
|  | from = (struct sockaddr *) | 
|  | malloc(fromlen32 ? *fromlen32 : sizeof(*from2)); | 
|  | memcpy(from, from2, fromlen32 ? *fromlen32 : sizeof(*from2)); | 
|  | from2->sipx_family = WS_AF_IPX; | 
|  | from2->sipx_network = ((struct sockaddr_ipx *)from)->sipx_network; | 
|  | from2->sipx_port = ((struct sockaddr_ipx *)from)->sipx_port; | 
|  | memcpy(from2->sipx_node, | 
|  | ((struct sockaddr_ipx *)from)->sipx_node, IPX_NODE_LEN); | 
|  | free(from); | 
|  | } | 
|  | #endif | 
|  | return (INT16)length; | 
|  | } | 
|  | pwsi->err = wsaErrno(); | 
|  | } | 
|  | else if( pwsi ) pwsi->err = WSAENOTSOCK; | 
|  | WARN(winsock, " -> ERROR\n"); | 
|  | #ifdef HAVE_IPX | 
|  | if (from && ((struct sockaddr_ipx *)from)->sipx_family == AF_IPX) { | 
|  | from = (struct sockaddr *) | 
|  | malloc(fromlen32 ? *fromlen32 : sizeof(*from2)); | 
|  | memcpy(from, from2, fromlen32 ? *fromlen32 : sizeof(*from2)); | 
|  | from2->sipx_family = WS_AF_IPX; | 
|  | from2->sipx_network = ((struct sockaddr_ipx *)from)->sipx_network; | 
|  | from2->sipx_port = ((struct sockaddr_ipx *)from)->sipx_port; | 
|  | memcpy(from2->sipx_node, | 
|  | ((struct sockaddr_ipx *)from)->sipx_node, IPX_NODE_LEN); | 
|  | free(from); | 
|  | } | 
|  | #endif | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              recvfrom()		(WINSOCK.17) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_recvfrom16(SOCKET16 s, char *buf, INT16 len, INT16 flags, | 
|  | struct sockaddr *from, INT16 *fromlen16) | 
|  | { | 
|  | INT fromlen32; | 
|  | INT *p = &fromlen32; | 
|  | INT retVal; | 
|  |  | 
|  | if( fromlen16 ) fromlen32 = *fromlen16; else p = NULL; | 
|  | retVal = WINSOCK_recvfrom( s, buf, len, flags, from, p ); | 
|  | if( fromlen16 ) *fromlen16 = fromlen32; | 
|  | return (INT16)retVal; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		select()		(WINSOCK.18)(WSOCK32.18) | 
|  | */ | 
|  | static INT __ws_select( BOOL b32, void *ws_readfds, void *ws_writefds, void *ws_exceptfds, | 
|  | struct timeval *timeout ) | 
|  | { | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): read %8x, write %8x, excp %8x\n", | 
|  | (unsigned) pwsi, (unsigned) ws_readfds, (unsigned) ws_writefds, (unsigned) ws_exceptfds); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | int         highfd = 0; | 
|  | fd_set      readfds, writefds, exceptfds; | 
|  | fd_set     *p_read, *p_write, *p_except; | 
|  |  | 
|  | p_read = fd_set_import(&readfds, pwsi, ws_readfds, &highfd, b32); | 
|  | p_write = fd_set_import(&writefds, pwsi, ws_writefds, &highfd, b32); | 
|  | p_except = fd_set_import(&exceptfds, pwsi, ws_exceptfds, &highfd, b32); | 
|  |  | 
|  | if( (highfd = select(highfd + 1, p_read, p_write, p_except, timeout)) > 0 ) | 
|  | { | 
|  | fd_set_export(pwsi, &readfds, p_except, ws_readfds, b32); | 
|  | fd_set_export(pwsi, &writefds, p_except, ws_writefds, b32); | 
|  |  | 
|  | if (p_except && ws_exceptfds) | 
|  | { | 
|  | #define wsfds16 ((ws_fd_set16*)ws_exceptfds) | 
|  | #define wsfds32 ((ws_fd_set32*)ws_exceptfds) | 
|  | int i, j, count = (b32) ? wsfds32->fd_count : wsfds16->fd_count; | 
|  |  | 
|  | for (i = j = 0; i < count; i++) | 
|  | { | 
|  | ws_socket *pws = (b32) ? (ws_socket *)WS_HANDLE2PTR(wsfds32->fd_array[i]) | 
|  | : (ws_socket *)WS_HANDLE2PTR(wsfds16->fd_array[i]); | 
|  | if( _check_ws(pwsi, pws) && FD_ISSET(pws->fd, &exceptfds) ) | 
|  | { | 
|  | if( b32 ) | 
|  | wsfds32->fd_array[j++] = wsfds32->fd_array[i]; | 
|  | else | 
|  | wsfds16->fd_array[j++] = wsfds16->fd_array[i]; | 
|  | } | 
|  | } | 
|  | if( b32 ) | 
|  | wsfds32->fd_count = j; | 
|  | else | 
|  | wsfds16->fd_count = j; | 
|  | #undef wsfds32 | 
|  | #undef wsfds16 | 
|  | } | 
|  | return highfd; | 
|  | } | 
|  | if( ws_readfds ) ((ws_fd_set32*)ws_readfds)->fd_count = 0; | 
|  | if( ws_writefds ) ((ws_fd_set32*)ws_writefds)->fd_count = 0; | 
|  | if( ws_exceptfds ) ((ws_fd_set32*)ws_exceptfds)->fd_count = 0; | 
|  |  | 
|  | if( highfd == 0 ) return 0; | 
|  | pwsi->err = wsaErrno(); | 
|  | } | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | INT16 WINAPI WINSOCK_select16(INT16 nfds, ws_fd_set16 *ws_readfds, | 
|  | ws_fd_set16 *ws_writefds, ws_fd_set16 *ws_exceptfds, | 
|  | struct timeval *timeout) | 
|  | { | 
|  | return (INT16)__ws_select( FALSE, ws_readfds, ws_writefds, ws_exceptfds, timeout ); | 
|  | } | 
|  |  | 
|  | INT WINAPI WINSOCK_select(INT nfds, ws_fd_set32 *ws_readfds, | 
|  | ws_fd_set32 *ws_writefds, ws_fd_set32 *ws_exceptfds, | 
|  | struct timeval *timeout) | 
|  | { | 
|  | /* struct timeval is the same for both 32- and 16-bit code */ | 
|  | return (INT)__ws_select( TRUE, ws_readfds, ws_writefds, ws_exceptfds, timeout ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		send()			(WSOCK32.19) | 
|  | */ | 
|  | INT WINAPI WINSOCK_send(SOCKET s, char *buf, INT len, INT flags) | 
|  | { | 
|  | ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x, ptr %08x, length %d, flags %d\n", | 
|  | (unsigned)pwsi, s, (unsigned) buf, len, flags); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | int	length; | 
|  |  | 
|  | if ((length = send(pws->fd, buf, len, flags)) < 0 ) | 
|  | { | 
|  | pwsi->err = wsaErrno(); | 
|  | if( pwsi->err == WSAEWOULDBLOCK && | 
|  | pws->psop && pws->flags & WS_FD_WRITE ) | 
|  | EVENT_AddIO( pws->fd, EVENT_IO_WRITE );	/* reenabler */ | 
|  | } | 
|  | else return (INT16)length; | 
|  | } | 
|  | else if( pwsi ) pwsi->err = WSAENOTSOCK; | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              send()			(WINSOCK.19) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_send16(SOCKET16 s, char *buf, INT16 len, INT16 flags) | 
|  | { | 
|  | return WINSOCK_send( s, buf, len, flags ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		sendto()		(WSOCK32.20) | 
|  | */ | 
|  | INT WINAPI WINSOCK_sendto(SOCKET s, char *buf, INT len, INT flags, | 
|  | struct sockaddr *to, INT tolen) | 
|  | { | 
|  | ws_socket*               pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO                 pwsi = wsi_find(GetCurrentTask()); | 
|  | #ifdef HAVE_IPX | 
|  | struct ws_sockaddr_ipx*  to2 = (struct ws_sockaddr_ipx *)to; | 
|  | #endif | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x, ptr %08x, length %d, flags %d\n", | 
|  | (unsigned)pwsi, s, (unsigned) buf, len, flags); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | INT	length; | 
|  |  | 
|  | if (to && ((struct ws_sockaddr_ipx *)to)->sipx_family == WS_AF_PUP) | 
|  | ((struct ws_sockaddr_ipx *)to)->sipx_family = AF_UNSPEC; | 
|  | #ifdef HAVE_IPX | 
|  | else if (to && | 
|  | ((struct ws_sockaddr_ipx *)to)->sipx_family == WS_AF_IPX) | 
|  | { | 
|  | to = (struct sockaddr *) malloc(sizeof(struct sockaddr_ipx)); | 
|  | memset(to, '\0', sizeof(struct sockaddr_ipx)); | 
|  | ((struct sockaddr_ipx *)to)->sipx_family = AF_IPX; | 
|  | ((struct sockaddr_ipx *)to)->sipx_port = to2->sipx_port; | 
|  | ((struct sockaddr_ipx *)to)->sipx_network = to2->sipx_network; | 
|  | memcpy(((struct sockaddr_ipx *)to)->sipx_node, | 
|  | to2->sipx_node, IPX_NODE_LEN); | 
|  | tolen = sizeof(struct sockaddr_ipx); | 
|  | } | 
|  | #endif | 
|  | if ((length = sendto(pws->fd, buf, len, flags, to, tolen)) < 0 ) | 
|  | { | 
|  | pwsi->err = wsaErrno(); | 
|  | if( pwsi->err == WSAEWOULDBLOCK && | 
|  | pws->psop && pws->flags & WS_FD_WRITE ) | 
|  | EVENT_AddIO( pws->fd, EVENT_IO_WRITE ); /* reenabler */ | 
|  | } | 
|  | else { | 
|  | #ifdef HAVE_IPX | 
|  | if (to && ((struct sockaddr_ipx *)to)->sipx_family == AF_IPX) { | 
|  | free(to); | 
|  | } | 
|  | #endif | 
|  | return length; | 
|  | } | 
|  | } | 
|  | else if( pwsi ) pwsi->err = WSAENOTSOCK; | 
|  | #ifdef HAVE_IPX | 
|  | if (to && ((struct sockaddr_ipx *)to)->sipx_family == AF_IPX) { | 
|  | free(to); | 
|  | } | 
|  | #endif | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              sendto()		(WINSOCK.20) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_sendto16(SOCKET16 s, char *buf, INT16 len, INT16 flags, | 
|  | struct sockaddr *to, INT16 tolen) | 
|  | { | 
|  | return (INT16)WINSOCK_sendto( s, buf, len, flags, to, tolen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		setsockopt()		(WSOCK32.21) | 
|  | */ | 
|  | INT WINAPI WINSOCK_setsockopt(SOCKET16 s, INT level, INT optname, | 
|  | char *optval, INT optlen) | 
|  | { | 
|  | ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x, lev %d, opt %d, ptr %08x, len %d\n", | 
|  | (unsigned)pwsi, s, level, optname, (int) optval, optlen); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | struct	linger linger; | 
|  |  | 
|  | convert_sockopt(&level, &optname); | 
|  | if (optname == SO_LINGER && optval) { | 
|  | /* yes, uses unsigned short in both win16/win32 */ | 
|  | linger.l_onoff	= ((UINT16*)optval)[0]; | 
|  | linger.l_linger	= ((UINT16*)optval)[1]; | 
|  | /* FIXME: what is documented behavior if SO_LINGER optval | 
|  | is null?? */ | 
|  | optval = (char*)&linger; | 
|  | optlen = sizeof(struct linger); | 
|  | } | 
|  | if (setsockopt(pws->fd, level, optname, optval, optlen) == 0) return 0; | 
|  | pwsi->err = wsaErrno(); | 
|  | } | 
|  | else if( pwsi ) pwsi->err = WSAENOTSOCK; | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              setsockopt()		(WINSOCK.21) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_setsockopt16(SOCKET16 s, INT16 level, INT16 optname, | 
|  | char *optval, INT16 optlen) | 
|  | { | 
|  | if( !optval ) return SOCKET_ERROR; | 
|  | return (INT16)WINSOCK_setsockopt( s, (UINT16)level, optname, optval, optlen ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		shutdown()		(WSOCK32.22) | 
|  | */ | 
|  | INT WINAPI WINSOCK_shutdown(SOCKET s, INT how) | 
|  | { | 
|  | ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): socket %04x, how %i\n", | 
|  | (unsigned)pwsi, s, how ); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | if( pws->psop ) | 
|  | switch( how ) | 
|  | { | 
|  | case 0: /* drop receives */ | 
|  | if( pws->flags & (WS_FD_READ | WS_FD_CLOSE) ) | 
|  | EVENT_DeleteIO( pws->fd, EVENT_IO_READ ); | 
|  | pws->flags &= ~(WS_FD_READ | WS_FD_CLOSE); | 
|  | #ifdef SHUT_RD | 
|  | how = SHUT_RD; | 
|  | #endif | 
|  | break; | 
|  |  | 
|  | case 1: /* drop sends */ | 
|  | if( pws->flags & WS_FD_WRITE ) | 
|  | EVENT_DeleteIO( pws->fd, EVENT_IO_WRITE ); | 
|  | pws->flags &= ~WS_FD_WRITE; | 
|  | #ifdef SHUT_WR | 
|  | how = SHUT_WR; | 
|  | #endif | 
|  | break; | 
|  |  | 
|  | case 2: /* drop all */ | 
|  | #ifdef SHUT_RDWR | 
|  | how = SHUT_RDWR; | 
|  | #endif | 
|  | default: | 
|  | WSAAsyncSelect( s, 0, 0, 0 ); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (shutdown(pws->fd, how) == 0) | 
|  | { | 
|  | if( how > 1 ) | 
|  | { | 
|  | pws->flags &= ~(WS_FD_CONNECTED | WS_FD_LISTENING); | 
|  | pws->flags |= WS_FD_INACTIVE; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  | pwsi->err = wsaErrno(); | 
|  | } | 
|  | else if( pwsi ) pwsi->err = WSAENOTSOCK; | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              shutdown()		(WINSOCK.22) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_shutdown16(SOCKET16 s, INT16 how) | 
|  | { | 
|  | return (INT16)WINSOCK_shutdown( s, how ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		socket()		(WSOCK32.23) | 
|  | */ | 
|  | SOCKET WINAPI WINSOCK_socket(INT af, INT type, INT protocol) | 
|  | { | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): af=%d type=%d protocol=%d\n", | 
|  | (unsigned)pwsi, af, type, protocol); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | int		sock; | 
|  |  | 
|  | /* check the socket family */ | 
|  | switch(af) | 
|  | { | 
|  | #ifdef HAVE_IPX | 
|  | case WS_AF_IPX:	af = AF_IPX; | 
|  | #endif | 
|  | case AF_INET: | 
|  | case AF_UNSPEC: break; | 
|  | default:        pwsi->err = WSAEAFNOSUPPORT; | 
|  | return INVALID_SOCKET; | 
|  | } | 
|  |  | 
|  | /* check the socket type */ | 
|  | switch(type) | 
|  | { | 
|  | case SOCK_STREAM: | 
|  | case SOCK_DGRAM: | 
|  | case SOCK_RAW:  break; | 
|  | default:        pwsi->err = WSAESOCKTNOSUPPORT; | 
|  | return INVALID_SOCKET; | 
|  | } | 
|  |  | 
|  | /* check the protocol type */ | 
|  | if ( protocol < 0 )  /* don't support negative values */ | 
|  | { pwsi->err = WSAEPROTONOSUPPORT; return INVALID_SOCKET; } | 
|  |  | 
|  | if ( af == AF_UNSPEC)  /* did they not specify the address family? */ | 
|  | switch(protocol) | 
|  | { | 
|  | case IPPROTO_TCP: | 
|  | if (type == SOCK_STREAM) { af = AF_INET; break; } | 
|  | case IPPROTO_UDP: | 
|  | if (type == SOCK_DGRAM)  { af = AF_INET; break; } | 
|  | default: pwsi->err = WSAEPROTOTYPE; return INVALID_SOCKET; | 
|  | } | 
|  |  | 
|  | if ((sock = socket(af, type, protocol)) >= 0) | 
|  | { | 
|  | ws_socket*      pnew = wsi_alloc_socket(pwsi, sock); | 
|  |  | 
|  | TRACE(winsock,"\tcreated %i (handle %04x)\n", sock, (UINT16)WS_PTR2HANDLE(pnew)); | 
|  |  | 
|  | if( pnew ) | 
|  | { | 
|  | pnew->flags |= WS_FD_INACTIVE; | 
|  | return (SOCKET16)WS_PTR2HANDLE(pnew); | 
|  | } | 
|  |  | 
|  | close(sock); | 
|  | pwsi->err = WSAENOBUFS; | 
|  | return INVALID_SOCKET; | 
|  | } | 
|  |  | 
|  | if (errno == EPERM) /* raw socket denied */ | 
|  | { | 
|  | WARN(winsock, "WS_SOCKET: not enough privileges\n"); | 
|  | pwsi->err = WSAESOCKTNOSUPPORT; | 
|  | } else pwsi->err = wsaErrno(); | 
|  | } | 
|  |  | 
|  | WARN(winsock, "\t\tfailed!\n"); | 
|  | return INVALID_SOCKET; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              socket()		(WINSOCK.23) | 
|  | */ | 
|  | SOCKET16 WINAPI WINSOCK_socket16(INT16 af, INT16 type, INT16 protocol) | 
|  | { | 
|  | return (SOCKET16)WINSOCK_socket( af, type, protocol ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ----------------------------------- DNS services | 
|  | * | 
|  | * IMPORTANT: 16-bit API structures have SEGPTR pointers inside them. | 
|  | * Also, we have to use wsock32 stubs to convert structures and | 
|  | * error codes from Unix to WSA, hence there is no direct mapping in | 
|  | * the relay32/wsock32.spec. | 
|  | */ | 
|  |  | 
|  | static char*	NULL_STRING = "NULL"; | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		gethostbyaddr()		(WINSOCK.51)(WSOCK32.51) | 
|  | */ | 
|  | static struct WIN_hostent* __ws_gethostbyaddr(const char *addr, int len, int type, int dup_flag) | 
|  | { | 
|  | LPWSINFO      	pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | struct hostent*	host; | 
|  | if( (host = gethostbyaddr(addr, len, type)) != NULL ) | 
|  | if( WS_dup_he(pwsi, host, dup_flag) ) | 
|  | return (struct WIN_hostent*)(pwsi->he); | 
|  | else | 
|  | pwsi->err = WSAENOBUFS; | 
|  | else | 
|  | pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | SEGPTR WINAPI WINSOCK_gethostbyaddr16(const char *addr, INT16 len, INT16 type) | 
|  | { | 
|  | struct WIN_hostent* retval; | 
|  | TRACE(winsock, "ptr %08x, len %d, type %d\n", | 
|  | (unsigned) addr, len, type); | 
|  | retval = __ws_gethostbyaddr( addr, len, type, WS_DUP_SEGPTR ); | 
|  | return retval ? SEGPTR_GET(retval) : ((SEGPTR)NULL); | 
|  | } | 
|  |  | 
|  | struct WIN_hostent* WINAPI WINSOCK_gethostbyaddr(const char *addr, INT len, | 
|  | INT type) | 
|  | { | 
|  | TRACE(winsock, "ptr %08x, len %d, type %d\n", | 
|  | (unsigned) addr, len, type); | 
|  | return __ws_gethostbyaddr(addr, len, type, WS_DUP_LINEAR); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		gethostbyname()		(WINSOCK.52)(WSOCK32.52) | 
|  | */ | 
|  | static struct WIN_hostent * __ws_gethostbyname(const char *name, int dup_flag) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | struct hostent*     host; | 
|  | if( (host = gethostbyname(name)) != NULL ) | 
|  | if( WS_dup_he(pwsi, host, dup_flag) ) | 
|  | return (struct WIN_hostent*)(pwsi->he); | 
|  | else pwsi->err = WSAENOBUFS; | 
|  | else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | SEGPTR WINAPI WINSOCK_gethostbyname16(const char *name) | 
|  | { | 
|  | struct WIN_hostent* retval; | 
|  | TRACE(winsock, "%s\n", (name)?name:NULL_STRING); | 
|  | retval = __ws_gethostbyname( name, WS_DUP_SEGPTR ); | 
|  | return (retval)? SEGPTR_GET(retval) : ((SEGPTR)NULL) ; | 
|  | } | 
|  |  | 
|  | struct WIN_hostent* WINAPI WINSOCK_gethostbyname(const char* name) | 
|  | { | 
|  | TRACE(winsock, "%s\n", (name)?name:NULL_STRING); | 
|  | return __ws_gethostbyname( name, WS_DUP_LINEAR ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getprotobyname()	(WINSOCK.53)(WSOCK32.53) | 
|  | */ | 
|  | static struct WIN_protoent* __ws_getprotobyname(const char *name, int dup_flag) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | struct protoent*     proto; | 
|  | if( (proto = getprotobyname(name)) != NULL ) | 
|  | if( WS_dup_pe(pwsi, proto, dup_flag) ) | 
|  | return (struct WIN_protoent*)(pwsi->pe); | 
|  | else pwsi->err = WSAENOBUFS; | 
|  | else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | SEGPTR WINAPI WINSOCK_getprotobyname16(const char *name) | 
|  | { | 
|  | struct WIN_protoent* retval; | 
|  | TRACE(winsock, "%s\n", (name)?name:NULL_STRING); | 
|  | retval = __ws_getprotobyname(name, WS_DUP_SEGPTR); | 
|  | return retval ? SEGPTR_GET(retval) : ((SEGPTR)NULL); | 
|  | } | 
|  |  | 
|  | struct WIN_protoent* WINAPI WINSOCK_getprotobyname(const char* name) | 
|  | { | 
|  | TRACE(winsock, "%s\n", (name)?name:NULL_STRING); | 
|  | return __ws_getprotobyname(name, WS_DUP_LINEAR); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getprotobynumber()	(WINSOCK.54)(WSOCK32.54) | 
|  | */ | 
|  | static struct WIN_protoent* __ws_getprotobynumber(int number, int dup_flag) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | struct protoent*     proto; | 
|  | if( (proto = getprotobynumber(number)) != NULL ) | 
|  | if( WS_dup_pe(pwsi, proto, dup_flag) ) | 
|  | return (struct WIN_protoent*)(pwsi->pe); | 
|  | else pwsi->err = WSAENOBUFS; | 
|  | else pwsi->err = WSANO_DATA; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | SEGPTR WINAPI WINSOCK_getprotobynumber16(INT16 number) | 
|  | { | 
|  | struct WIN_protoent* retval; | 
|  | TRACE(winsock, "%i\n", number); | 
|  | retval = __ws_getprotobynumber(number, WS_DUP_SEGPTR); | 
|  | return retval ? SEGPTR_GET(retval) : ((SEGPTR)NULL); | 
|  | } | 
|  |  | 
|  | struct WIN_protoent* WINAPI WINSOCK_getprotobynumber(INT number) | 
|  | { | 
|  | TRACE(winsock, "%i\n", number); | 
|  | return __ws_getprotobynumber(number, WS_DUP_LINEAR); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getservbyname()		(WINSOCK.55)(WSOCK32.55) | 
|  | */ | 
|  | struct WIN_servent* __ws_getservbyname(const char *name, const char *proto, int dup_flag) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | struct servent*     serv; | 
|  | int i = wsi_strtolo( pwsi, name, proto ); | 
|  |  | 
|  | if( i ) | 
|  | if( (serv = getservbyname(pwsi->buffer, pwsi->buffer + i)) != NULL ) | 
|  | if( WS_dup_se(pwsi, serv, dup_flag) ) | 
|  | return (struct WIN_servent*)(pwsi->se); | 
|  | else pwsi->err = WSAENOBUFS; | 
|  | else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); | 
|  | else pwsi->err = WSAENOBUFS; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | SEGPTR WINAPI WINSOCK_getservbyname16(const char *name, const char *proto) | 
|  | { | 
|  | struct WIN_servent* retval; | 
|  | TRACE(winsock, "'%s', '%s'\n", | 
|  | (name)?name:NULL_STRING, (proto)?proto:NULL_STRING); | 
|  | retval = __ws_getservbyname(name, proto, WS_DUP_SEGPTR); | 
|  | return retval ? SEGPTR_GET(retval) : ((SEGPTR)NULL); | 
|  | } | 
|  |  | 
|  | struct WIN_servent* WINAPI WINSOCK_getservbyname(const char *name, const char *proto) | 
|  | { | 
|  | TRACE(winsock, "'%s', '%s'\n", | 
|  | (name)?name:NULL_STRING, (proto)?proto:NULL_STRING); | 
|  | return __ws_getservbyname(name, proto, WS_DUP_LINEAR); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getservbyport()		(WINSOCK.56)(WSOCK32.56) | 
|  | */ | 
|  | static struct WIN_servent* __ws_getservbyport(int port, const char* proto, int dup_flag) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | struct servent*     serv; | 
|  | int i = wsi_strtolo( pwsi, proto, NULL ); | 
|  |  | 
|  | if( i ) | 
|  | if( (serv = getservbyport(port, pwsi->buffer)) != NULL ) | 
|  | if( WS_dup_se(pwsi, serv, dup_flag) ) | 
|  | return (struct WIN_servent*)(pwsi->se); | 
|  | else pwsi->err = WSAENOBUFS; | 
|  | else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); | 
|  | else pwsi->err = WSAENOBUFS; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | SEGPTR WINAPI WINSOCK_getservbyport16(INT16 port, const char *proto) | 
|  | { | 
|  | struct WIN_servent* retval; | 
|  | TRACE(winsock, "%i, '%s'\n", | 
|  | (int)port, (proto)?proto:NULL_STRING); | 
|  | retval = __ws_getservbyport(port, proto, WS_DUP_SEGPTR); | 
|  | return retval ? SEGPTR_GET(retval) : ((SEGPTR)NULL); | 
|  | } | 
|  |  | 
|  | struct WIN_servent* WINAPI WINSOCK_getservbyport(INT port, const char *proto) | 
|  | { | 
|  | TRACE(winsock, "%i, '%s'\n", | 
|  | (int)port, (proto)?proto:NULL_STRING); | 
|  | return __ws_getservbyport(port, proto, WS_DUP_LINEAR); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              gethostname()           (WSOCK32.57) | 
|  | */ | 
|  | INT WINAPI WINSOCK_gethostname(char *name, INT namelen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): name %s, len %d\n", | 
|  | (unsigned)pwsi, (name)?name:NULL_STRING, namelen); | 
|  | if( pwsi ) | 
|  | { | 
|  | if (gethostname(name, namelen) == 0) return 0; | 
|  | pwsi->err = (errno == EINVAL) ? WSAEFAULT : wsaErrno(); | 
|  | } | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              gethostname()           (WINSOCK.57) | 
|  | */ | 
|  | INT16 WINAPI WINSOCK_gethostname16(char *name, INT16 namelen) | 
|  | { | 
|  | return (INT16)WINSOCK_gethostname(name, namelen); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ------------------------------------- Windows sockets extensions -- * | 
|  | *								       * | 
|  | * ------------------------------------------------------------------- */ | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetHostByAddr()	(WINSOCK.102) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetHostByAddr16(HWND16 hWnd, UINT16 uMsg, LPCSTR addr, | 
|  | INT16 len, INT16 type, SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %04x, addr %08x[%i]\n", | 
|  | (unsigned)pwsi, hWnd, uMsg, (unsigned)addr , len ); | 
|  |  | 
|  | if( pwsi ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, type, addr, len, | 
|  | NULL, (void*)sbuf, buflen, WSMSG_ASYNC_HOSTBYADDR ); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetHostByAddr()        (WSOCK32.102) | 
|  | */ | 
|  | HANDLE WINAPI WSAAsyncGetHostByAddr(HWND hWnd, UINT uMsg, LPCSTR addr, | 
|  | INT len, INT type, LPSTR sbuf, INT buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %08x, addr %08x[%i]\n", | 
|  | (unsigned)pwsi, (HWND16)hWnd, uMsg, (unsigned)addr , len ); | 
|  |  | 
|  | if( pwsi ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, type, addr, len, | 
|  | NULL, (void*)sbuf, buflen, WSMSG_ASYNC_HOSTBYADDR | WSMSG_WIN32_AOP); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetHostByName()	(WINSOCK.103) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetHostByName16(HWND16 hWnd, UINT16 uMsg, LPCSTR name, | 
|  | SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %04x, host %s, | 
|  | buffer %i\n", (unsigned)pwsi, hWnd, uMsg, (name)?name:NULL_STRING, (int)buflen ); | 
|  |  | 
|  | if( pwsi ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, 0, name, 0, | 
|  | NULL, (void*)sbuf, buflen, WSMSG_ASYNC_HOSTBYNAME ); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetHostByName32()	(WSOCK32.103) | 
|  | */ | 
|  | HANDLE WINAPI WSAAsyncGetHostByName(HWND hWnd, UINT uMsg, LPCSTR name, | 
|  | LPSTR sbuf, INT buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %08x, host %s, buffer %i\n", | 
|  | (unsigned)pwsi, (HWND16)hWnd, uMsg, | 
|  | (name)?name:NULL_STRING, (int)buflen ); | 
|  | if( pwsi ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, 0, name, 0, | 
|  | NULL, (void*)sbuf, buflen, WSMSG_ASYNC_HOSTBYNAME | WSMSG_WIN32_AOP); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetProtoByName()	(WINSOCK.105) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetProtoByName16(HWND16 hWnd, UINT16 uMsg, LPCSTR name, | 
|  | SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %08x, protocol %s\n", | 
|  | (unsigned)pwsi, (HWND16)hWnd, uMsg, (name)?name:NULL_STRING ); | 
|  |  | 
|  | if( pwsi ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, 0, name, 0, | 
|  | NULL, (void*)sbuf, buflen, WSMSG_ASYNC_PROTOBYNAME ); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetProtoByName()       (WSOCK32.105) | 
|  | */ | 
|  | HANDLE WINAPI WSAAsyncGetProtoByName(HWND hWnd, UINT uMsg, LPCSTR name, | 
|  | LPSTR sbuf, INT buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %08x, protocol %s\n", | 
|  | (unsigned)pwsi, (HWND16)hWnd, uMsg, (name)?name:NULL_STRING ); | 
|  |  | 
|  | if( pwsi ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, 0, name, 0, | 
|  | NULL, (void*)sbuf, buflen, WSMSG_ASYNC_PROTOBYNAME | WSMSG_WIN32_AOP); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetProtoByNumber()	(WINSOCK.104) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetProtoByNumber16(HWND16 hWnd, UINT16 uMsg, INT16 number, | 
|  | SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %04x, num %i\n", | 
|  | (unsigned)pwsi, hWnd, uMsg, number ); | 
|  |  | 
|  | if( pwsi ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, number, NULL, 0, | 
|  | NULL, (void*)sbuf, buflen, WSMSG_ASYNC_PROTOBYNUM ); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetProtoByNumber()     (WSOCK32.104) | 
|  | */ | 
|  | HANDLE WINAPI WSAAsyncGetProtoByNumber(HWND hWnd, UINT uMsg, INT number, | 
|  | LPSTR sbuf, INT buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %08x, num %i\n", | 
|  | (unsigned)pwsi, (HWND16)hWnd, uMsg, number ); | 
|  |  | 
|  | if( pwsi ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, number, NULL, 0, | 
|  | NULL, (void*)sbuf, buflen, WSMSG_ASYNC_PROTOBYNUM | WSMSG_WIN32_AOP); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetServByName()	(WINSOCK.107) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetServByName16(HWND16 hWnd, UINT16 uMsg, LPCSTR name, | 
|  | LPCSTR proto, SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %04x, name %s, proto %s\n", | 
|  | (unsigned)pwsi, hWnd, uMsg, | 
|  | (name)?name:NULL_STRING, (proto)?proto:NULL_STRING ); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | int i = wsi_strtolo( pwsi, name, proto ); | 
|  |  | 
|  | if( i ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, 0, pwsi->buffer, 0, | 
|  | pwsi->buffer + i, (void*)sbuf, buflen, WSMSG_ASYNC_SERVBYNAME ); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetServByName()        (WSOCK32.107) | 
|  | */ | 
|  | HANDLE WINAPI WSAAsyncGetServByName(HWND hWnd, UINT uMsg, LPCSTR name, | 
|  | LPCSTR proto, LPSTR sbuf, INT buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %08x, name %s, proto %s\n", | 
|  | (unsigned)pwsi, (HWND16)hWnd, uMsg, | 
|  | (name)?name:NULL_STRING, (proto)?proto:NULL_STRING ); | 
|  | if( pwsi ) | 
|  | { | 
|  | int i = wsi_strtolo( pwsi, name, proto ); | 
|  |  | 
|  | if( i ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, 0, pwsi->buffer, 0, | 
|  | pwsi->buffer + i, (void*)sbuf, buflen, WSMSG_ASYNC_SERVBYNAME | WSMSG_WIN32_AOP); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetServByPort()	(WINSOCK.106) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetServByPort16(HWND16 hWnd, UINT16 uMsg, INT16 port, | 
|  | LPCSTR proto, SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %04x, port %i, proto %s\n", | 
|  | (unsigned)pwsi, hWnd, uMsg, port, (proto)?proto:NULL_STRING ); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | int i = wsi_strtolo( pwsi, proto, NULL ); | 
|  |  | 
|  | if( i ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, port, pwsi->buffer, 0, | 
|  | NULL, (void*)sbuf, buflen, WSMSG_ASYNC_SERVBYPORT ); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetServByPort()        (WSOCK32.106) | 
|  | */ | 
|  | HANDLE WINAPI WSAAsyncGetServByPort(HWND hWnd, UINT uMsg, INT port, | 
|  | LPCSTR proto, LPSTR sbuf, INT buflen) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hwnd %04x, msg %08x, port %i, proto %s\n", | 
|  | (unsigned)pwsi, (HWND16)hWnd, uMsg, port, (proto)?proto:NULL_STRING ); | 
|  |  | 
|  | if( pwsi ) | 
|  | { | 
|  | int i = wsi_strtolo( pwsi, proto, NULL ); | 
|  |  | 
|  | if( i ) | 
|  | return __WSAsyncDBQuery(pwsi, hWnd, uMsg, port, pwsi->buffer, 0, | 
|  | NULL, (void*)sbuf, buflen, WSMSG_ASYNC_SERVBYPORT | WSMSG_WIN32_AOP); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSACancelAsyncRequest()	(WINSOCK.108)(WSOCK32.109) | 
|  | */ | 
|  | INT WINAPI WSACancelAsyncRequest(HANDLE hAsyncTaskHandle) | 
|  | { | 
|  | INT		retVal = SOCKET_ERROR; | 
|  | LPWSINFO		pwsi = wsi_find(GetCurrentTask()); | 
|  | ws_async_op*	p_aop = (ws_async_op*)WS_HANDLE2PTR(hAsyncTaskHandle); | 
|  |  | 
|  | TRACE(winsock, "(%08x): handle %08x\n", | 
|  | (unsigned)pwsi, hAsyncTaskHandle); | 
|  | if( pwsi ) | 
|  | { | 
|  | SIGNAL_MaskAsyncEvents( TRUE );	/* block SIGIO */ | 
|  | if( WINSOCK_cancel_async_op(p_aop) ) | 
|  | { | 
|  | WS_FREE(p_aop); | 
|  | pwsi->num_async_rq--; | 
|  | retVal = 0; | 
|  | } | 
|  | else pwsi->err = WSAEINVAL; | 
|  | SIGNAL_MaskAsyncEvents( FALSE ); | 
|  | } | 
|  | return retVal; | 
|  | } | 
|  |  | 
|  | INT16 WINAPI WSACancelAsyncRequest16(HANDLE16 hAsyncTaskHandle) | 
|  | { | 
|  | return (HANDLE16)WSACancelAsyncRequest((HANDLE)hAsyncTaskHandle); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAAsyncSelect()		(WINSOCK.101)(WSOCK32.101) | 
|  | */ | 
|  |  | 
|  | static ws_select_op* __ws_select_list = NULL; | 
|  |  | 
|  | BOOL WINSOCK_HandleIO( int* max_fd, int num_pending, | 
|  | fd_set pending_set[3], fd_set event_set[3] ) | 
|  | { | 
|  | /* This function is called by the event dispatcher | 
|  | * with the pending_set[] containing the result of select() and | 
|  | * the event_set[] containing all fd that are being watched */ | 
|  |  | 
|  | ws_select_op*	psop = __ws_select_list; | 
|  | BOOL		bPost = FALSE; | 
|  | DWORD		dwEvent, dwErrBytes; | 
|  | int			num_posted; | 
|  |  | 
|  | TRACE(winsock,"%i pending descriptors\n", num_pending ); | 
|  |  | 
|  | for( num_posted = dwEvent = 0 ; psop; psop = psop->next ) | 
|  | { | 
|  | unsigned	flags = psop->pws->flags; | 
|  | int		fd = psop->pws->fd; | 
|  | int		r, w, e; | 
|  |  | 
|  | w = 0; | 
|  | if( (r = FD_ISSET( fd, &pending_set[EVENT_IO_READ] )) || | 
|  | (w = FD_ISSET( fd, &pending_set[EVENT_IO_WRITE] )) || | 
|  | (e = FD_ISSET( fd, &pending_set[EVENT_IO_EXCEPT] )) ) | 
|  | { | 
|  | /* This code removes WS_FD flags on one-shot events (WS_FD_CLOSE, | 
|  | * WS_FD_CONNECT), otherwise it clears descriptors in the io_set. | 
|  | * Reenabling calls turn them back on. | 
|  | */ | 
|  |  | 
|  | TRACE(winsock,"\tchecking psop = 0x%08x\n", (unsigned) psop ); | 
|  |  | 
|  | num_pending--; | 
|  |  | 
|  | /* Now figure out what kind of event we've got. The worst problem | 
|  | * we have to contend with is that some out of control applications | 
|  | * really want to use mutually exclusive AsyncSelect() flags all at | 
|  | * the same time. | 
|  | */ | 
|  |  | 
|  | if((flags & WS_FD_ACCEPT) && (flags & WS_FD_LISTENING)) | 
|  | { | 
|  | /* WS_FD_ACCEPT is valid only if the socket is in the | 
|  | * listening state */ | 
|  |  | 
|  | FD_CLR( fd, &event_set[EVENT_IO_WRITE] ); | 
|  | if( r ) | 
|  | { | 
|  | FD_CLR( fd, &event_set[EVENT_IO_READ] ); /* reenabled by the next accept() */ | 
|  | dwEvent = WSAMAKESELECTREPLY( WS_FD_ACCEPT, 0 ); | 
|  | bPost = TRUE; | 
|  | } | 
|  | else continue; | 
|  | } | 
|  | else if( flags & WS_FD_CONNECT ) | 
|  | { | 
|  | /* connecting socket */ | 
|  |  | 
|  | if( w || (w = FD_ISSET( fd, &pending_set[EVENT_IO_WRITE] )) ) | 
|  | { | 
|  | /* ready to write means that socket is connected | 
|  | * | 
|  | * FIXME: Netscape calls AsyncSelect( s, ... WS_FD_CONNECT .. ) | 
|  | * right after s = socket() and somehow "s" becomes writeable | 
|  | * before it goes through connect()!?!? | 
|  | */ | 
|  |  | 
|  | psop->pws->flags |= WS_FD_CONNECTED; | 
|  | psop->pws->flags &= ~(WS_FD_CONNECT | WS_FD_INACTIVE); | 
|  | dwEvent = WSAMAKESELECTREPLY( WS_FD_CONNECT, 0 ); | 
|  |  | 
|  | if( flags & (WS_FD_READ | WS_FD_CLOSE)) | 
|  | FD_SET( fd, &event_set[EVENT_IO_READ] ); | 
|  | else | 
|  | FD_CLR( fd, &event_set[EVENT_IO_READ] ); | 
|  | if( flags & WS_FD_WRITE ) | 
|  | FD_SET( fd, &event_set[EVENT_IO_WRITE] ); | 
|  | else | 
|  | FD_CLR( fd, &event_set[EVENT_IO_WRITE] ); | 
|  | bPost = TRUE; | 
|  | } | 
|  | else if( r ) | 
|  | { | 
|  | /* failure - do read() to get correct errno */ | 
|  |  | 
|  | if( read( fd, &dwErrBytes, sizeof(dwErrBytes) ) == -1 ) | 
|  | { | 
|  | dwEvent = WSAMAKESELECTREPLY( WS_FD_CONNECT, wsaErrno() ); | 
|  | bPost = TRUE; | 
|  | } | 
|  | } | 
|  | /* otherwise bPost stays FALSE, should probably clear event_set  */ | 
|  | } | 
|  | else | 
|  | { | 
|  | /* connected socket, no WS_FD_OOB code for now. */ | 
|  |  | 
|  | if( flags & WS_FD_WRITE && | 
|  | (w || (w = FD_ISSET( fd, &pending_set[EVENT_IO_WRITE] ))) ) | 
|  | { | 
|  | /* this will be reenabled when send() or sendto() fail with | 
|  | * WSAEWOULDBLOCK */ | 
|  |  | 
|  | if( PostMessageA( psop->hWnd, psop->uMsg, (WPARAM)WS_PTR2HANDLE(psop->pws), | 
|  | (LPARAM)WSAMAKESELECTREPLY( WS_FD_WRITE, 0 ) ) ) | 
|  | { | 
|  | TRACE(winsock, "\t    hwnd %04x - %04x, %08x\n", | 
|  | psop->hWnd, psop->uMsg, (unsigned)MAKELONG(WS_FD_WRITE, 0) ); | 
|  | FD_CLR( fd, &event_set[EVENT_IO_WRITE] ); | 
|  | num_posted++; | 
|  | } | 
|  | } | 
|  |  | 
|  | if( r && (flags & (WS_FD_READ | WS_FD_CLOSE)) ) | 
|  | { | 
|  | int val = (flags & WS_FD_RAW); | 
|  |  | 
|  | /* WS_FD_RAW is set by the WSAAsyncSelect() init */ | 
|  |  | 
|  | bPost = TRUE; | 
|  | if( !val && ioctl( fd, FIONREAD, (char*)&dwErrBytes) == -1 ) | 
|  | { | 
|  | /* weirdness */ | 
|  |  | 
|  | dwEvent = WSAMAKESELECTREPLY( WS_FD_READ, wsaErrno() ); | 
|  | } | 
|  | else if( val || dwErrBytes ) | 
|  | { | 
|  | /* got pending data, will be reenabled by recv() or recvfrom() */ | 
|  |  | 
|  | FD_CLR( fd, &event_set[EVENT_IO_READ] ); | 
|  | dwEvent = WSAMAKESELECTREPLY( WS_FD_READ, 0 ); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* 0 bytes to read - connection reset by peer? */ | 
|  |  | 
|  | do | 
|  | val = read( fd, (char*)&dwErrBytes, sizeof(dwErrBytes)); | 
|  | while( errno == EINTR ); | 
|  | if( errno != EWOULDBLOCK ) | 
|  | { | 
|  | switch( val ) | 
|  | { | 
|  | case  0: errno = ENETDOWN;	/* soft reset, fall through */ | 
|  | case -1: 			/* hard reset */ | 
|  | dwEvent = WSAMAKESELECTREPLY( WS_FD_CLOSE, wsaErrno() ); | 
|  | break; | 
|  |  | 
|  | default: bPost = FALSE; | 
|  | continue;		/* FIXME: this is real bad */ | 
|  | } | 
|  | } | 
|  | else { bPost = FALSE; continue; }	/* more weirdness */ | 
|  |  | 
|  | /* this is it, this socket is closed */ | 
|  |  | 
|  | psop->pws->flags &= ~(WS_FD_READ | WS_FD_CLOSE | WS_FD_WRITE); | 
|  | FD_CLR( fd, &event_set[EVENT_IO_READ] ); | 
|  | FD_CLR( fd, &event_set[EVENT_IO_WRITE] ); | 
|  |  | 
|  | if( *max_fd == (fd + 1) ) (*max_fd)--; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if( bPost ) | 
|  | { | 
|  | TRACE(winsock, "\t    hwnd %04x - %04x, %08x\n", | 
|  | psop->hWnd, psop->uMsg, (unsigned)dwEvent ); | 
|  | PostMessageA( psop->hWnd, psop->uMsg, | 
|  | (WPARAM)WS_PTR2HANDLE(psop->pws), (LPARAM)dwEvent ); | 
|  | bPost = FALSE; | 
|  | num_posted++; | 
|  | } | 
|  | } | 
|  | if( num_pending <= 0 ) break; | 
|  | } | 
|  |  | 
|  | TRACE(winsock, "\tdone, %i posted events\n", num_posted ); | 
|  | return ( num_posted ) ? TRUE : FALSE; | 
|  | } | 
|  |  | 
|  | INT WINAPI WSAAsyncSelect(SOCKET s, HWND hWnd, UINT uMsg, UINT lEvent) | 
|  | { | 
|  | ws_socket*    pws  = (ws_socket*)WS_HANDLE2PTR(s); | 
|  | LPWSINFO      pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): %04x, hWnd %04x, uMsg %08x, event %08x\n", | 
|  | (unsigned)pwsi, (SOCKET16)s, (HWND16)hWnd, uMsg, (unsigned)lEvent ); | 
|  | if( _check_ws(pwsi, pws) ) | 
|  | { | 
|  | ws_select_op* psop; | 
|  |  | 
|  | if( (psop = pws->psop) ) | 
|  | { | 
|  | /* delete previous control struct */ | 
|  |  | 
|  | if( psop == __ws_select_list ) | 
|  | __ws_select_list = psop->next; | 
|  | else | 
|  | psop->prev->next = psop->next; | 
|  | if( psop->next ) psop->next->prev = psop->prev; | 
|  |  | 
|  | if( pws->flags & (WS_FD_ACCEPT | WS_FD_CONNECT | WS_FD_READ | WS_FD_CLOSE) ) | 
|  | EVENT_DeleteIO( pws->fd, EVENT_IO_READ ); | 
|  | if( pws->flags & (WS_FD_CONNECT | WS_FD_WRITE) ) | 
|  | EVENT_DeleteIO( pws->fd, EVENT_IO_WRITE ); | 
|  |  | 
|  | TRACE(winsock,"\tremoving psop = 0x%08x\n", (unsigned) psop ); | 
|  |  | 
|  | WS_FREE( pws->psop ); | 
|  | pws->flags &= ~(WS_FD_RAW | WS_FD_ACCEPT | WS_FD_CONNECT | | 
|  | WS_FD_READ | WS_FD_WRITE | WS_FD_CLOSE); | 
|  | pws->psop = NULL; | 
|  | } | 
|  |  | 
|  | if( lEvent ) | 
|  | { | 
|  | psop = (ws_select_op*)WS_ALLOC(sizeof(ws_select_op)); | 
|  | if( psop ) | 
|  | { | 
|  | int sock_type, bytes = sizeof(int); | 
|  |  | 
|  | WINSOCK_unblock_io( pws->fd, TRUE ); | 
|  |  | 
|  | psop->prev = NULL; | 
|  | psop->next = __ws_select_list; | 
|  | if( __ws_select_list ) | 
|  | __ws_select_list->prev = psop; | 
|  | __ws_select_list = psop; | 
|  |  | 
|  | psop->pws = pws; | 
|  | psop->hWnd = hWnd; | 
|  | psop->uMsg = uMsg; | 
|  |  | 
|  | pws->psop = psop; | 
|  | pws->flags |= (0x0000FFFF & lEvent); | 
|  | getsockopt(pws->fd, SOL_SOCKET, SO_TYPE, &sock_type, &bytes); | 
|  | if( sock_type == SOCK_RAW ) pws->flags |= WS_FD_RAW; | 
|  |  | 
|  | if( lEvent & (WS_FD_ACCEPT | WS_FD_CONNECT | WS_FD_READ | WS_FD_CLOSE) ) | 
|  | EVENT_AddIO( pws->fd, EVENT_IO_READ ); | 
|  | if( lEvent & (WS_FD_CONNECT | WS_FD_WRITE) ) | 
|  | EVENT_AddIO( pws->fd, EVENT_IO_WRITE ); | 
|  |  | 
|  | /* TODO: handle WS_FD_ACCEPT right away if the socket is readable */ | 
|  |  | 
|  | TRACE(winsock,"\tcreating psop = 0x%08x\n", (unsigned)psop ); | 
|  |  | 
|  | return 0; /* success */ | 
|  | } | 
|  | else pwsi->err = WSAENOBUFS; | 
|  | } | 
|  | else return 0; | 
|  | } | 
|  | else if( pwsi ) pwsi->err = WSAEINVAL; | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | INT16 WINAPI WSAAsyncSelect16(SOCKET16 s, HWND16 hWnd, UINT16 wMsg, UINT lEvent) | 
|  | { | 
|  | return (INT16)WSAAsyncSelect( s, hWnd, wMsg, lEvent ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *	__WSAFDIsSet()			(WINSOCK.151) | 
|  | */ | 
|  | INT16 WINAPI __WSAFDIsSet16(SOCKET16 s, ws_fd_set16 *set) | 
|  | { | 
|  | int i = set->fd_count; | 
|  |  | 
|  | TRACE(winsock, "(%d,%8lx(%i))\n", s,(unsigned long)set, i); | 
|  |  | 
|  | while (i--) | 
|  | if (set->fd_array[i] == s) return 1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      __WSAFDIsSet()			(WSOCK32.151) | 
|  | */ | 
|  | INT WINAPI __WSAFDIsSet(SOCKET s, ws_fd_set32 *set) | 
|  | { | 
|  | int i = set->fd_count; | 
|  |  | 
|  | TRACE(winsock, "(%d,%8lx(%i))\n", s,(unsigned long)set, i); | 
|  |  | 
|  | while (i--) | 
|  | if (set->fd_array[i] == s) return 1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAIsBlocking()			(WINSOCK.114)(WSOCK32.114) | 
|  | */ | 
|  | BOOL WINAPI WSAIsBlocking(void) | 
|  | { | 
|  | /* By default WinSock should set all its sockets to non-blocking mode | 
|  | * and poll in PeekMessage loop when processing "blocking" ones. This | 
|  | * function is supposed to tell if the program is in this loop. Our | 
|  | * blocking calls are truly blocking so we always return FALSE. | 
|  | * | 
|  | * Note: It is allowed to call this function without prior WSAStartup(). | 
|  | */ | 
|  |  | 
|  | TRACE(winsock, "\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSACancelBlockingCall()		(WINSOCK.113)(WSOCK32.113) | 
|  | */ | 
|  | INT WINAPI WSACancelBlockingCall(void) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x)\n", (unsigned)pwsi); | 
|  |  | 
|  | if( pwsi ) return 0; | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSASetBlockingHook16()		(WINSOCK.109) | 
|  | */ | 
|  | FARPROC16 WINAPI WSASetBlockingHook16(FARPROC16 lpBlockFunc) | 
|  | { | 
|  | FARPROC16		prev; | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hook %08x\n", | 
|  | (unsigned)pwsi, (unsigned) lpBlockFunc); | 
|  | if( pwsi ) | 
|  | { | 
|  | prev = (FARPROC16)pwsi->blocking_hook; | 
|  | pwsi->blocking_hook = (DWORD)lpBlockFunc; | 
|  | pwsi->flags &= ~WSI_BLOCKINGHOOK; | 
|  | return prev; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSASetBlockingHook32() | 
|  | */ | 
|  | FARPROC WINAPI WSASetBlockingHook(FARPROC lpBlockFunc) | 
|  | { | 
|  | FARPROC             prev; | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x): hook %08x\n", | 
|  | (unsigned)pwsi, (unsigned) lpBlockFunc); | 
|  | if( pwsi ) { | 
|  | prev = (FARPROC)pwsi->blocking_hook; | 
|  | pwsi->blocking_hook = (DWORD)lpBlockFunc; | 
|  | pwsi->flags |= WSI_BLOCKINGHOOK; | 
|  | return prev; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAUnhookBlockingHook16()	(WINSOCK.110) | 
|  | */ | 
|  | INT16 WINAPI WSAUnhookBlockingHook16(void) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x)\n", (unsigned)pwsi); | 
|  | if( pwsi ) return (INT16)(pwsi->blocking_hook = 0); | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAUnhookBlockingHook32() | 
|  | */ | 
|  | INT WINAPI WSAUnhookBlockingHook(void) | 
|  | { | 
|  | LPWSINFO              pwsi = wsi_find(GetCurrentTask()); | 
|  |  | 
|  | TRACE(winsock, "(%08x)\n", (unsigned)pwsi); | 
|  | if( pwsi ) | 
|  | { | 
|  | pwsi->blocking_hook = 0; | 
|  | pwsi->flags &= ~WSI_BLOCKINGHOOK; | 
|  | return 0; | 
|  | } | 
|  | return SOCKET_ERROR; | 
|  | } | 
|  |  | 
|  | /* | 
|  | *      TCP/IP action codes. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #define WSCNTL_TCPIP_QUERY_INFO             0x00000000 | 
|  | #define WSCNTL_TCPIP_SET_INFO               0x00000001 | 
|  | #define WSCNTL_TCPIP_ICMP_ECHO              0x00000002 | 
|  | #define WSCNTL_TCPIP_TEST                   0x00000003 | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WsControl() | 
|  | * | 
|  | * WsControl seems to be an undocumented Win95 function. A lot of | 
|  | * discussion about WsControl can be found on the net, e.g. | 
|  | * Subject:      Re: WSOCK32.DLL WsControl Exported Function | 
|  | * From:         "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de> | 
|  | * Date:         1997/08/17 | 
|  | */ | 
|  |  | 
|  | DWORD WINAPI WsControl(DWORD protocoll,DWORD action, | 
|  | LPVOID inbuf,LPDWORD inbuflen, | 
|  | LPVOID outbuf,LPDWORD outbuflen) | 
|  | { | 
|  |  | 
|  | switch (action) { | 
|  | case WSCNTL_TCPIP_ICMP_ECHO: | 
|  | { | 
|  | unsigned int addr = *(unsigned int*)inbuf; | 
|  | #if 0 | 
|  | int timeout= *(unsigned int*)(inbuf+4); | 
|  | short x1 = *(unsigned short*)(inbuf+8); | 
|  | short sendbufsize = *(unsigned short*)(inbuf+10); | 
|  | char x2 = *(unsigned char*)(inbuf+12); | 
|  | char ttl = *(unsigned char*)(inbuf+13); | 
|  | char service = *(unsigned char*)(inbuf+14); | 
|  | char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/ | 
|  | #endif | 
|  |  | 
|  | FIXME(winsock,"(ICMP_ECHO) to 0x%08x stub \n", addr); | 
|  | break; | 
|  | } | 
|  | default: | 
|  | FIXME(winsock,"(%lx,%lx,%p,%p,%p,%p) stub\n", | 
|  | protocoll,action,inbuf,inbuflen,outbuf,outbuflen); | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  | /********************************************************* | 
|  | *       WS_s_perror         WSOCK32.1108 | 
|  | */ | 
|  | void WINAPI WS_s_perror(LPCSTR message) | 
|  | { | 
|  | FIXME(winsock,"(%s): stub\n",message); | 
|  | return; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* ----------------------------------- end of API stuff */ | 
|  |  | 
|  | /* ----------------------------------- helper functions - | 
|  | * | 
|  | * TODO: Merge WS_dup_..() stuff into one function that | 
|  | * would operate with a generic structure containing internal | 
|  | * pointers (via a template of some kind). | 
|  | */ | 
|  |  | 
|  | static int list_size(char** l, int item_size) | 
|  | { | 
|  | int i,j = 0; | 
|  | if(l) | 
|  | { for(i=0;l[i];i++) | 
|  | j += (item_size) ? item_size : strlen(l[i]) + 1; | 
|  | j += (i + 1) * sizeof(char*); } | 
|  | return j; | 
|  | } | 
|  |  | 
|  | static int list_dup(char** l_src, char* ref, char* base, int item_size) | 
|  | { | 
|  | /* base is either either equal to ref or 0 or SEGPTR */ | 
|  |  | 
|  | char*		p = ref; | 
|  | char**		l_to = (char**)ref; | 
|  | int			i,j,k; | 
|  |  | 
|  | for(j=0;l_src[j];j++) ; | 
|  | p += (j + 1) * sizeof(char*); | 
|  | for(i=0;i<j;i++) | 
|  | { l_to[i] = base + (p - ref); | 
|  | k = ( item_size ) ? item_size : strlen(l_src[i]) + 1; | 
|  | memcpy(p, l_src[i], k); p += k; } | 
|  | l_to[i] = NULL; | 
|  | return (p - ref); | 
|  | } | 
|  |  | 
|  | /* ----- hostent */ | 
|  |  | 
|  | static int hostent_size(struct hostent* p_he) | 
|  | { | 
|  | int size = 0; | 
|  | if( p_he ) | 
|  | { size  = sizeof(struct hostent); | 
|  | size += strlen(p_he->h_name) + 1; | 
|  | size += list_size(p_he->h_aliases, 0); | 
|  | size += list_size(p_he->h_addr_list, p_he->h_length ); } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | int WS_dup_he(LPWSINFO pwsi, struct hostent* p_he, int flag) | 
|  | { | 
|  | /* Convert hostent structure into ws_hostent so that the data fits | 
|  | * into pwsi->buffer. Internal pointers can be linear, SEGPTR, or | 
|  | * relative to pwsi->buffer depending on "flag" value. Returns size | 
|  | * of the data copied (also in the pwsi->buflen). | 
|  | */ | 
|  |  | 
|  | int size = hostent_size(p_he); | 
|  |  | 
|  | if( size ) | 
|  | { | 
|  | struct ws_hostent* p_to; | 
|  | char* p_name,*p_aliases,*p_addr,*p_base,*p; | 
|  |  | 
|  | _check_buffer_he(pwsi, size); | 
|  | p_to = (struct ws_hostent*)pwsi->he; | 
|  | p = (char*)pwsi->he; | 
|  | p_base = (flag & WS_DUP_OFFSET) ? NULL | 
|  | : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p); | 
|  | p += sizeof(struct ws_hostent); | 
|  | p_name = p; | 
|  | strcpy(p, p_he->h_name); p += strlen(p) + 1; | 
|  | p_aliases = p; | 
|  | p += list_dup(p_he->h_aliases, p, p_base + (p - (char*)pwsi->he), 0); | 
|  | p_addr = p; | 
|  | list_dup(p_he->h_addr_list, p, p_base + (p - (char*)pwsi->he), p_he->h_length); | 
|  |  | 
|  | p_to->h_addrtype = (INT16)p_he->h_addrtype; | 
|  | p_to->h_length = (INT16)p_he->h_length; | 
|  | p_to->h_name = (SEGPTR)(p_base + (p_name - (char*)pwsi->he)); | 
|  | p_to->h_aliases = (SEGPTR)(p_base + (p_aliases - (char*)pwsi->he)); | 
|  | p_to->h_addr_list = (SEGPTR)(p_base + (p_addr - (char*)pwsi->he)); | 
|  |  | 
|  | size += (sizeof(struct ws_hostent) - sizeof(struct hostent)); | 
|  | } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | /* ----- protoent */ | 
|  |  | 
|  | static int protoent_size(struct protoent* p_pe) | 
|  | { | 
|  | int size = 0; | 
|  | if( p_pe ) | 
|  | { size  = sizeof(struct protoent); | 
|  | size += strlen(p_pe->p_name) + 1; | 
|  | size += list_size(p_pe->p_aliases, 0); } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | int WS_dup_pe(LPWSINFO pwsi, struct protoent* p_pe, int flag) | 
|  | { | 
|  | int size = protoent_size(p_pe); | 
|  | if( size ) | 
|  | { | 
|  | struct ws_protoent* p_to; | 
|  | char* p_name,*p_aliases,*p_base,*p; | 
|  |  | 
|  | _check_buffer_pe(pwsi, size); | 
|  | p_to = (struct ws_protoent*)pwsi->pe; | 
|  | p = (char*)pwsi->pe; | 
|  | p_base = (flag & WS_DUP_OFFSET) ? NULL | 
|  | : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p); | 
|  | p += sizeof(struct ws_protoent); | 
|  | p_name = p; | 
|  | strcpy(p, p_pe->p_name); p += strlen(p) + 1; | 
|  | p_aliases = p; | 
|  | list_dup(p_pe->p_aliases, p, p_base + (p - (char*)pwsi->pe), 0); | 
|  |  | 
|  | p_to->p_proto = (INT16)p_pe->p_proto; | 
|  | p_to->p_name = (SEGPTR)(p_base) + (p_name - (char*)pwsi->pe); | 
|  | p_to->p_aliases = (SEGPTR)((p_base) + (p_aliases - (char*)pwsi->pe)); | 
|  |  | 
|  | size += (sizeof(struct ws_protoent) - sizeof(struct protoent)); | 
|  | } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | /* ----- servent */ | 
|  |  | 
|  | static int servent_size(struct servent* p_se) | 
|  | { | 
|  | int size = 0; | 
|  | if( p_se ) | 
|  | { size += sizeof(struct servent); | 
|  | size += strlen(p_se->s_proto) + strlen(p_se->s_name) + 2; | 
|  | size += list_size(p_se->s_aliases, 0); } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | int WS_dup_se(LPWSINFO pwsi, struct servent* p_se, int flag) | 
|  | { | 
|  | int size = servent_size(p_se); | 
|  | if( size ) | 
|  | { | 
|  | struct ws_servent* p_to; | 
|  | char* p_name,*p_aliases,*p_proto,*p_base,*p; | 
|  |  | 
|  | _check_buffer_se(pwsi, size); | 
|  | p_to = (struct ws_servent*)pwsi->se; | 
|  | p = (char*)pwsi->se; | 
|  | p_base = (flag & WS_DUP_OFFSET) ? NULL | 
|  | : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p); | 
|  | p += sizeof(struct ws_servent); | 
|  | p_name = p; | 
|  | strcpy(p, p_se->s_name); p += strlen(p) + 1; | 
|  | p_proto = p; | 
|  | strcpy(p, p_se->s_proto); p += strlen(p) + 1; | 
|  | p_aliases = p; | 
|  | list_dup(p_se->s_aliases, p, p_base + (p - (char*)pwsi->se), 0); | 
|  |  | 
|  | p_to->s_port = (INT16)p_se->s_port; | 
|  | p_to->s_name = (SEGPTR)(p_base + (p_name - (char*)pwsi->se)); | 
|  | p_to->s_proto = (SEGPTR)(p_base + (p_proto - (char*)pwsi->se)); | 
|  | p_to->s_aliases = (SEGPTR)(p_base + (p_aliases - (char*)pwsi->se)); | 
|  |  | 
|  | size += (sizeof(struct ws_servent) - sizeof(struct servent)); | 
|  | } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | /* ----------------------------------- error handling */ | 
|  |  | 
|  | UINT16 wsaErrno(void) | 
|  | { | 
|  | int	loc_errno = errno; | 
|  | #ifdef HAVE_STRERROR | 
|  | WARN(winsock, "errno %d, (%s).\n", loc_errno, strerror(loc_errno)); | 
|  | #else | 
|  | WARN(winsock, "errno %d\n", loc_errno); | 
|  | #endif | 
|  |  | 
|  | switch(loc_errno) | 
|  | { | 
|  | case EINTR:		return WSAEINTR; | 
|  | case EBADF:		return WSAEBADF; | 
|  | case EACCES:		return WSAEACCES; | 
|  | case EFAULT:		return WSAEFAULT; | 
|  | case EINVAL:		return WSAEINVAL; | 
|  | case EMFILE:		return WSAEMFILE; | 
|  | case EWOULDBLOCK:	return WSAEWOULDBLOCK; | 
|  | case EINPROGRESS:	return WSAEINPROGRESS; | 
|  | case EALREADY:		return WSAEALREADY; | 
|  | case ENOTSOCK:		return WSAENOTSOCK; | 
|  | case EDESTADDRREQ:	return WSAEDESTADDRREQ; | 
|  | case EMSGSIZE:		return WSAEMSGSIZE; | 
|  | case EPROTOTYPE:	return WSAEPROTOTYPE; | 
|  | case ENOPROTOOPT:	return WSAENOPROTOOPT; | 
|  | case EPROTONOSUPPORT:	return WSAEPROTONOSUPPORT; | 
|  | case ESOCKTNOSUPPORT:	return WSAESOCKTNOSUPPORT; | 
|  | case EOPNOTSUPP:	return WSAEOPNOTSUPP; | 
|  | case EPFNOSUPPORT:	return WSAEPFNOSUPPORT; | 
|  | case EAFNOSUPPORT:	return WSAEAFNOSUPPORT; | 
|  | case EADDRINUSE:	return WSAEADDRINUSE; | 
|  | case EADDRNOTAVAIL:	return WSAEADDRNOTAVAIL; | 
|  | case ENETDOWN:		return WSAENETDOWN; | 
|  | case ENETUNREACH:	return WSAENETUNREACH; | 
|  | case ENETRESET:		return WSAENETRESET; | 
|  | case ECONNABORTED:	return WSAECONNABORTED; | 
|  | case EPIPE: | 
|  | case ECONNRESET:	return WSAECONNRESET; | 
|  | case ENOBUFS:		return WSAENOBUFS; | 
|  | case EISCONN:		return WSAEISCONN; | 
|  | case ENOTCONN:		return WSAENOTCONN; | 
|  | case ESHUTDOWN:		return WSAESHUTDOWN; | 
|  | case ETOOMANYREFS:	return WSAETOOMANYREFS; | 
|  | case ETIMEDOUT:		return WSAETIMEDOUT; | 
|  | case ECONNREFUSED:	return WSAECONNREFUSED; | 
|  | case ELOOP:		return WSAELOOP; | 
|  | case ENAMETOOLONG:	return WSAENAMETOOLONG; | 
|  | case EHOSTDOWN:		return WSAEHOSTDOWN; | 
|  | case EHOSTUNREACH:	return WSAEHOSTUNREACH; | 
|  | case ENOTEMPTY:		return WSAENOTEMPTY; | 
|  | #ifdef EPROCLIM | 
|  | case EPROCLIM:		return WSAEPROCLIM; | 
|  | #endif | 
|  | #ifdef EUSERS | 
|  | case EUSERS:		return WSAEUSERS; | 
|  | #endif | 
|  | #ifdef EDQUOT | 
|  | case EDQUOT:		return WSAEDQUOT; | 
|  | #endif | 
|  | #ifdef ESTALE | 
|  | case ESTALE:		return WSAESTALE; | 
|  | #endif | 
|  | #ifdef EREMOTE | 
|  | case EREMOTE:		return WSAEREMOTE; | 
|  | #endif | 
|  |  | 
|  | /* just in case we ever get here and there are no problems */ | 
|  | case 0:			return 0; | 
|  | default: | 
|  | WARN(winsock, "Unknown errno %d!\n", loc_errno); | 
|  | return WSAEOPNOTSUPP; | 
|  | } | 
|  | } | 
|  |  | 
|  | UINT16 wsaHerrno(void) | 
|  | { | 
|  | int		loc_errno = h_errno; | 
|  |  | 
|  | WARN(winsock, "h_errno %d.\n", loc_errno); | 
|  |  | 
|  | switch(loc_errno) | 
|  | { | 
|  | case HOST_NOT_FOUND:	return WSAHOST_NOT_FOUND; | 
|  | case TRY_AGAIN:		return WSATRY_AGAIN; | 
|  | case NO_RECOVERY:	return WSANO_RECOVERY; | 
|  | case NO_DATA:		return WSANO_DATA; | 
|  |  | 
|  | case 0:			return 0; | 
|  | default: | 
|  | WARN(winsock,"Unknown h_errno %d!\n", loc_errno); | 
|  | return WSAEOPNOTSUPP; | 
|  | } | 
|  | } |