|  | /* | 
|  | * 16-bit socket functions | 
|  | * | 
|  | * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka | 
|  | * Copyright (C) 2003 Alexandre Julliard | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #include "winsock2.h" | 
|  | #include "wine/winbase16.h" | 
|  | #include "winsock16.h" | 
|  | #include "wownt32.h" | 
|  | #include "winuser.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(winsock); | 
|  |  | 
|  | struct async_query_header | 
|  | { | 
|  | HWND     hWnd; | 
|  | UINT     uMsg; | 
|  | SEGPTR   sbuf; | 
|  | INT      sbuflen; | 
|  | HANDLE16 handle; | 
|  | }; | 
|  |  | 
|  | struct async_query_gethostbyname | 
|  | { | 
|  | struct async_query_header query; | 
|  | char *host_name; | 
|  | }; | 
|  |  | 
|  | struct async_query_gethostbyaddr | 
|  | { | 
|  | struct async_query_header query; | 
|  | char *host_addr; | 
|  | int   host_len; | 
|  | int   host_type; | 
|  | }; | 
|  |  | 
|  | struct async_query_getprotobyname | 
|  | { | 
|  | struct async_query_header query; | 
|  | char *proto_name; | 
|  | }; | 
|  |  | 
|  | struct async_query_getprotobynumber | 
|  | { | 
|  | struct async_query_header query; | 
|  | int   proto_number; | 
|  | }; | 
|  |  | 
|  | struct async_query_getservbyname | 
|  | { | 
|  | struct async_query_header query; | 
|  | char *serv_name; | 
|  | char *serv_proto; | 
|  | }; | 
|  |  | 
|  | struct async_query_getservbyport | 
|  | { | 
|  | struct async_query_header query; | 
|  | char *serv_proto; | 
|  | int   serv_port; | 
|  | }; | 
|  |  | 
|  | static INT num_startup;  /* reference counter */ | 
|  | static void *he_buffer; | 
|  | static SEGPTR he_buffer_seg; | 
|  | static void *se_buffer; | 
|  | static SEGPTR se_buffer_seg; | 
|  | static void *pe_buffer; | 
|  | static SEGPTR pe_buffer_seg; | 
|  | static SEGPTR dbuffer_seg; | 
|  |  | 
|  | extern int WINAPI WS_gethostname(char *name, int namelen); | 
|  |  | 
|  | static fd_set *ws_fdset_16_to_32( const ws_fd_set16 *set16, fd_set *set32 ) | 
|  | { | 
|  | UINT i; | 
|  | set32->fd_count = set16->fd_count; | 
|  | for (i = 0; i < set32->fd_count; i++) set32->fd_array[i] = set16->fd_array[i]; | 
|  | return set32; | 
|  | } | 
|  |  | 
|  | static ws_fd_set16 *ws_fdset_32_to_16( const fd_set *set32, ws_fd_set16 *set16 ) | 
|  | { | 
|  | UINT i; | 
|  | set16->fd_count = set32->fd_count; | 
|  | for (i = 0; i < set16->fd_count; i++) set16->fd_array[i] = set32->fd_array[i]; | 
|  | return set16; | 
|  | } | 
|  |  | 
|  | static DWORD finish_query( struct async_query_header *query, LPARAM lparam ) | 
|  | { | 
|  | PostMessageW( query->hWnd, query->uMsg, (WPARAM)query->handle, lparam ); | 
|  | HeapFree( GetProcessHeap(), 0, query ); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | 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, SEGPTR base, int item_size) | 
|  | { | 
|  | int i, offset; | 
|  | char *ref = MapSL(base); | 
|  | SEGPTR *l_to = (SEGPTR *)ref; | 
|  |  | 
|  | for (i = 0; l_src[i]; i++) ; | 
|  | offset = (i + 1) * sizeof(char*); | 
|  | for (i = 0; l_src[i]; i++) | 
|  | { | 
|  | int count = item_size ? item_size : strlen(l_src[i]) + 1; | 
|  | memcpy( ref + offset, l_src[i], count ); | 
|  | l_to[i] = base + offset; | 
|  | offset += count; | 
|  | } | 
|  | l_to[i] = 0; | 
|  | return offset; | 
|  | } | 
|  |  | 
|  | static SEGPTR get_buffer_he(int size) | 
|  | { | 
|  | static int he_len; | 
|  | if (he_buffer) | 
|  | { | 
|  | if (he_len >= size ) return he_buffer_seg; | 
|  | UnMapLS( he_buffer_seg ); | 
|  | HeapFree( GetProcessHeap(), 0, he_buffer ); | 
|  | } | 
|  | he_buffer = HeapAlloc( GetProcessHeap(), 0, (he_len = size) ); | 
|  | he_buffer_seg = MapLS( he_buffer ); | 
|  | return he_buffer_seg; | 
|  | } | 
|  |  | 
|  | static SEGPTR get_buffer_se(int size) | 
|  | { | 
|  | static int se_len; | 
|  | if (se_buffer) | 
|  | { | 
|  | if (se_len >= size ) return se_buffer_seg; | 
|  | UnMapLS( se_buffer_seg ); | 
|  | HeapFree( GetProcessHeap(), 0, se_buffer ); | 
|  | } | 
|  | se_buffer = HeapAlloc( GetProcessHeap(), 0, (se_len = size) ); | 
|  | se_buffer_seg = MapLS( se_buffer ); | 
|  | return se_buffer_seg; | 
|  | } | 
|  |  | 
|  | static SEGPTR get_buffer_pe(int size) | 
|  | { | 
|  | static int pe_len; | 
|  | if (pe_buffer) | 
|  | { | 
|  | if (pe_len >= size ) return pe_buffer_seg; | 
|  | UnMapLS( pe_buffer_seg ); | 
|  | HeapFree( GetProcessHeap(), 0, pe_buffer ); | 
|  | } | 
|  | pe_buffer = HeapAlloc( GetProcessHeap(), 0, (pe_len = size) ); | 
|  | pe_buffer_seg = MapLS( pe_buffer ); | 
|  | return pe_buffer_seg; | 
|  | } | 
|  |  | 
|  | /* duplicate hostent entry | 
|  | * and handle all Win16/Win32 dependent things (struct size, ...) *correctly*. | 
|  | * Ditto for protoent and servent. | 
|  | */ | 
|  | static SEGPTR ws_hostent_32_to_16( const struct hostent* he, SEGPTR base, int *buff_size ) | 
|  | { | 
|  | char *p; | 
|  | struct ws_hostent16 *p_to; | 
|  |  | 
|  | int size = (sizeof(*p_to) + | 
|  | strlen(he->h_name) + 1 + | 
|  | list_size(he->h_aliases, 0) + | 
|  | list_size(he->h_addr_list, he->h_length)); | 
|  |  | 
|  | if (buff_size) | 
|  | { | 
|  | if (*buff_size < size) | 
|  | { | 
|  | *buff_size = size; | 
|  | return 0; | 
|  | } | 
|  | *buff_size = size; | 
|  | } | 
|  | else base = get_buffer_he(size); | 
|  | p_to = MapSL(base); | 
|  |  | 
|  | p_to->h_addrtype = he->h_addrtype; | 
|  | p_to->h_length = he->h_length; | 
|  |  | 
|  | p = (char *)(p_to + 1); | 
|  | p_to->h_name = base + (p - (char *)p_to); | 
|  | strcpy(p, he->h_name); | 
|  | p += strlen(p) + 1; | 
|  |  | 
|  | p_to->h_aliases = base + (p - (char *)p_to); | 
|  | p += list_dup(he->h_aliases, p_to->h_aliases, 0); | 
|  |  | 
|  | p_to->h_addr_list = base + (p - (char *)p_to); | 
|  | list_dup(he->h_addr_list, p_to->h_addr_list, he->h_length); | 
|  |  | 
|  | return base; | 
|  | } | 
|  |  | 
|  | static SEGPTR ws_protoent_32_to_16( const struct protoent *pe, SEGPTR base, int *buff_size ) | 
|  | { | 
|  | char *p; | 
|  | struct ws_protoent16 *p_to; | 
|  |  | 
|  | int size = (sizeof(*p_to) + | 
|  | strlen(pe->p_name) + 1 + | 
|  | list_size(pe->p_aliases, 0)); | 
|  |  | 
|  | if (buff_size) | 
|  | { | 
|  | if (*buff_size < size) | 
|  | { | 
|  | *buff_size = size; | 
|  | return 0; | 
|  | } | 
|  | *buff_size = size; | 
|  | } | 
|  | else base = get_buffer_pe(size); | 
|  | p_to = MapSL(base); | 
|  |  | 
|  | p_to->p_proto = pe->p_proto; | 
|  | p = (char *)(p_to + 1); | 
|  |  | 
|  | p_to->p_name = base + (p - (char *)p_to); | 
|  | strcpy(p, pe->p_name); | 
|  | p += strlen(p) + 1; | 
|  |  | 
|  | p_to->p_aliases = base + (p - (char *)p_to); | 
|  | list_dup(pe->p_aliases, p_to->p_aliases, 0); | 
|  |  | 
|  | return base; | 
|  | } | 
|  |  | 
|  | static SEGPTR ws_servent_32_to_16( const struct servent *se, SEGPTR base, int *buff_size ) | 
|  | { | 
|  | char *p; | 
|  | struct ws_servent16 *p_to; | 
|  |  | 
|  | int size = (sizeof(*p_to) + | 
|  | strlen(se->s_proto) + 1 + | 
|  | strlen(se->s_name) + 1 + | 
|  | list_size(se->s_aliases, 0)); | 
|  |  | 
|  | if (buff_size) | 
|  | { | 
|  | if (*buff_size < size) | 
|  | { | 
|  | *buff_size = size; | 
|  | return 0; | 
|  | } | 
|  | *buff_size = size; | 
|  | } | 
|  | else base = get_buffer_se(size); | 
|  | p_to = MapSL(base); | 
|  |  | 
|  | p_to->s_port = se->s_port; | 
|  | p = (char *)(p_to + 1); | 
|  |  | 
|  | p_to->s_name = base + (p - (char *)p_to); | 
|  | strcpy(p, se->s_name); | 
|  | p += strlen(p) + 1; | 
|  |  | 
|  | p_to->s_proto = base + (p - (char *)p_to); | 
|  | strcpy(p, se->s_proto); | 
|  | p += strlen(p) + 1; | 
|  |  | 
|  | p_to->s_aliases = base + (p - (char *)p_to); | 
|  | list_dup(se->s_aliases, p_to->s_aliases, 0); | 
|  |  | 
|  | return base; | 
|  | } | 
|  |  | 
|  | static DWORD WINAPI async_gethostbyname(LPVOID arg) | 
|  | { | 
|  | struct async_query_gethostbyname *aq = arg; | 
|  | int size = 0; | 
|  | WORD fail = 0; | 
|  | struct hostent *he; | 
|  |  | 
|  | if ((he = gethostbyname( aq->host_name ))) | 
|  | { | 
|  | size = aq->query.sbuflen; | 
|  | if (!ws_hostent_32_to_16( he, aq->query.sbuf, &size )) fail = WSAENOBUFS; | 
|  | } | 
|  | else fail = GetLastError(); | 
|  |  | 
|  | return finish_query( &aq->query, MAKELPARAM( size, fail )); | 
|  | } | 
|  |  | 
|  | static DWORD WINAPI async_gethostbyaddr(LPVOID arg) | 
|  | { | 
|  | struct async_query_gethostbyaddr *aq = arg; | 
|  | int size = 0; | 
|  | WORD fail = 0; | 
|  | struct hostent *he; | 
|  |  | 
|  | if ((he = gethostbyaddr(aq->host_addr,aq->host_len,aq->host_type))) | 
|  | { | 
|  | size = aq->query.sbuflen; | 
|  | if (!ws_hostent_32_to_16( he, aq->query.sbuf, &size )) fail = WSAENOBUFS; | 
|  | } | 
|  | else fail = GetLastError(); | 
|  |  | 
|  | return finish_query( &aq->query, MAKELPARAM( size, fail )); | 
|  | } | 
|  |  | 
|  | static DWORD WINAPI async_getprotobyname(LPVOID arg) | 
|  | { | 
|  | struct async_query_getprotobyname *aq = arg; | 
|  | int size = 0; | 
|  | WORD fail = 0; | 
|  | struct protoent *pe; | 
|  |  | 
|  | if ((pe = getprotobyname(aq->proto_name))) | 
|  | { | 
|  | size = aq->query.sbuflen; | 
|  | if (!ws_protoent_32_to_16( pe, aq->query.sbuf, &size )) fail = WSAENOBUFS; | 
|  | } | 
|  | else fail = GetLastError(); | 
|  |  | 
|  | return finish_query( &aq->query, MAKELPARAM( size, fail )); | 
|  | } | 
|  |  | 
|  | static DWORD WINAPI async_getprotobynumber(LPVOID arg) | 
|  | { | 
|  | struct async_query_getprotobynumber *aq = arg; | 
|  | int size = 0; | 
|  | WORD fail = 0; | 
|  | struct protoent *pe; | 
|  |  | 
|  | if ((pe = getprotobynumber(aq->proto_number))) | 
|  | { | 
|  | size = aq->query.sbuflen; | 
|  | if (!ws_protoent_32_to_16( pe, aq->query.sbuf, &size )) fail = WSAENOBUFS; | 
|  | } | 
|  | else fail = GetLastError(); | 
|  |  | 
|  | return finish_query( &aq->query, MAKELPARAM( size, fail )); | 
|  | } | 
|  |  | 
|  | static DWORD WINAPI async_getservbyname(LPVOID arg) | 
|  | { | 
|  | struct async_query_getservbyname *aq = arg; | 
|  | int size = 0; | 
|  | WORD fail = 0; | 
|  | struct servent *se; | 
|  |  | 
|  | if ((se = getservbyname(aq->serv_name,aq->serv_proto))) | 
|  | { | 
|  | size = aq->query.sbuflen; | 
|  | if (!ws_servent_32_to_16( se, aq->query.sbuf, &size )) fail = WSAENOBUFS; | 
|  | } | 
|  | else fail = GetLastError(); | 
|  |  | 
|  | return finish_query( &aq->query, MAKELPARAM( size, fail )); | 
|  | } | 
|  |  | 
|  | static DWORD WINAPI async_getservbyport(LPVOID arg) | 
|  | { | 
|  | struct async_query_getservbyport *aq = arg; | 
|  | int size = 0; | 
|  | WORD fail = 0; | 
|  | struct servent *se; | 
|  |  | 
|  | if ((se = getservbyport(aq->serv_port,aq->serv_proto))) | 
|  | { | 
|  | size = aq->query.sbuflen; | 
|  | if (!ws_servent_32_to_16( se, aq->query.sbuf, &size )) fail = WSAENOBUFS; | 
|  | } | 
|  | else fail = GetLastError(); | 
|  |  | 
|  | return finish_query( &aq->query, MAKELPARAM( size, fail )); | 
|  | } | 
|  |  | 
|  | /**************************************************************************** | 
|  | * The main async help function. | 
|  | * | 
|  | * It either starts a thread or just calls the function directly for platforms | 
|  | * with no thread support. This relies on the fact that PostMessage() does | 
|  | * not actually call the windowproc before the function returns. | 
|  | */ | 
|  | static HANDLE16 run_query( HWND16 hWnd, UINT uMsg, LPTHREAD_START_ROUTINE func, | 
|  | struct async_query_header *query, SEGPTR sbuf, INT sbuflen ) | 
|  | { | 
|  | static LONG next_handle = 0xdead; | 
|  | HANDLE thread; | 
|  | ULONG handle = LOWORD( InterlockedIncrement( &next_handle )); | 
|  |  | 
|  | /* avoid handle 0 */ | 
|  | while (!handle) handle = LOWORD( InterlockedIncrement( &next_handle )); | 
|  |  | 
|  | query->hWnd    = HWND_32(hWnd); | 
|  | query->uMsg    = uMsg; | 
|  | query->handle  = handle; | 
|  | query->sbuf    = sbuf; | 
|  | query->sbuflen = sbuflen; | 
|  |  | 
|  | thread = CreateThread( NULL, 0, func, query, 0, NULL ); | 
|  | if (!thread) | 
|  | { | 
|  | SetLastError( WSAEWOULDBLOCK ); | 
|  | return 0; | 
|  | } | 
|  | CloseHandle( thread ); | 
|  | return handle; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              accept		(WINSOCK.1) | 
|  | */ | 
|  | SOCKET16 WINAPI accept16(SOCKET16 s, struct sockaddr* addr, INT16* addrlen16 ) | 
|  | { | 
|  | INT addrlen32 = addrlen16 ? *addrlen16 : 0; | 
|  | SOCKET retSocket = accept( s, addr, &addrlen32 ); | 
|  | if( addrlen16 ) *addrlen16 = addrlen32; | 
|  | return retSocket; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              bind			(WINSOCK.2) | 
|  | */ | 
|  | INT16 WINAPI bind16(SOCKET16 s, struct sockaddr *name, INT16 namelen) | 
|  | { | 
|  | return bind( s, name, namelen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              closesocket           (WINSOCK.3) | 
|  | */ | 
|  | INT16 WINAPI closesocket16(SOCKET16 s) | 
|  | { | 
|  | return closesocket(s); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              connect               (WINSOCK.4) | 
|  | */ | 
|  | INT16 WINAPI connect16(SOCKET16 s, struct sockaddr *name, INT16 namelen) | 
|  | { | 
|  | return connect( s, name, namelen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              getpeername		(WINSOCK.5) | 
|  | */ | 
|  | INT16 WINAPI getpeername16(SOCKET16 s, struct sockaddr *name, INT16 *namelen16) | 
|  | { | 
|  | INT namelen32 = *namelen16; | 
|  | INT retVal = getpeername( s, name, &namelen32 ); | 
|  | *namelen16 = namelen32; | 
|  | return retVal; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              getsockname		(WINSOCK.6) | 
|  | */ | 
|  | INT16 WINAPI getsockname16(SOCKET16 s, struct sockaddr *name, INT16 *namelen16) | 
|  | { | 
|  | INT retVal; | 
|  |  | 
|  | if( namelen16 ) | 
|  | { | 
|  | INT namelen32 = *namelen16; | 
|  | retVal = getsockname( s, name, &namelen32 ); | 
|  | *namelen16 = namelen32; | 
|  | } | 
|  | else retVal = SOCKET_ERROR; | 
|  | return retVal; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              getsockopt		(WINSOCK.7) | 
|  | */ | 
|  | INT16 WINAPI 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 = getsockopt( s, (WORD)level, optname, optval, p ); | 
|  | if( optlen ) *optlen = optlen32; | 
|  | return retVal; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		htonl			(WINSOCK.8) | 
|  | */ | 
|  | u_long WINAPI htonl16(u_long hostlong) | 
|  | { | 
|  | return htonl(hostlong); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		htons			(WINSOCK.9) | 
|  | */ | 
|  | u_short WINAPI htons16(u_short hostshort) | 
|  | { | 
|  | return htons(hostshort); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		inet_addr		(WINSOCK.10) | 
|  | */ | 
|  | u_long WINAPI inet_addr16(const char *cp) | 
|  | { | 
|  | if (!cp) return INADDR_NONE; | 
|  | return inet_addr(cp); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		inet_ntoa		(WINSOCK.11) | 
|  | */ | 
|  | SEGPTR WINAPI inet_ntoa16(struct in_addr in) | 
|  | { | 
|  | char* retVal; | 
|  | if (!(retVal = inet_ntoa( in ))) return 0; | 
|  | if (!dbuffer_seg) dbuffer_seg = MapLS( retVal ); | 
|  | return dbuffer_seg; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              ioctlsocket           (WINSOCK.12) | 
|  | */ | 
|  | INT16 WINAPI ioctlsocket16(SOCKET16 s, LONG cmd, u_long *argp) | 
|  | { | 
|  | return ioctlsocket( s, cmd, argp ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              listen		(WINSOCK.13) | 
|  | */ | 
|  | INT16 WINAPI listen16(SOCKET16 s, INT16 backlog) | 
|  | { | 
|  | return listen( s, backlog ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ntohl			(WINSOCK.14) | 
|  | */ | 
|  | u_long WINAPI ntohl16(u_long netlong) | 
|  | { | 
|  | return ntohl(netlong); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		ntohs			(WINSOCK.15) | 
|  | */ | 
|  | u_short WINAPI ntohs16(u_short netshort) | 
|  | { | 
|  | return ntohs(netshort); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              recv			(WINSOCK.16) | 
|  | */ | 
|  | INT16 WINAPI recv16(SOCKET16 s, char *buf, INT16 len, INT16 flags) | 
|  | { | 
|  | return recv( s, buf, len, flags ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              recvfrom		(WINSOCK.17) | 
|  | */ | 
|  | INT16 WINAPI recvfrom16(SOCKET16 s, char *buf, INT16 len, INT16 flags, | 
|  | struct sockaddr *from, INT16 *fromlen16) | 
|  | { | 
|  | if (fromlen16) | 
|  | { | 
|  | INT fromlen32 = *fromlen16; | 
|  | INT retVal = recvfrom( s, buf, len, flags, from, &fromlen32 ); | 
|  | *fromlen16 = fromlen32; | 
|  | return retVal; | 
|  | } | 
|  | else return recvfrom( s, buf, len, flags, from, NULL ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		select			(WINSOCK.18) | 
|  | */ | 
|  | INT16 WINAPI select16(INT16 nfds, ws_fd_set16 *ws_readfds, | 
|  | ws_fd_set16 *ws_writefds, ws_fd_set16 *ws_exceptfds, | 
|  | struct timeval* timeout) | 
|  | { | 
|  | fd_set read_set, write_set, except_set; | 
|  | fd_set *pread_set = NULL, *pwrite_set = NULL, *pexcept_set = NULL; | 
|  | int ret; | 
|  |  | 
|  | if (ws_readfds) pread_set = ws_fdset_16_to_32( ws_readfds, &read_set ); | 
|  | if (ws_writefds) pwrite_set = ws_fdset_16_to_32( ws_writefds, &write_set ); | 
|  | if (ws_exceptfds) pexcept_set = ws_fdset_16_to_32( ws_exceptfds, &except_set ); | 
|  | /* struct timeval is the same for both 32- and 16-bit code */ | 
|  | ret = select( nfds, pread_set, pwrite_set, pexcept_set, timeout ); | 
|  | if (ws_readfds) ws_fdset_32_to_16( &read_set, ws_readfds ); | 
|  | if (ws_writefds) ws_fdset_32_to_16( &write_set, ws_writefds ); | 
|  | if (ws_exceptfds) ws_fdset_32_to_16( &except_set, ws_exceptfds ); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              send			(WINSOCK.19) | 
|  | */ | 
|  | INT16 WINAPI send16(SOCKET16 s, char *buf, INT16 len, INT16 flags) | 
|  | { | 
|  | return send( s, buf, len, flags ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              sendto		(WINSOCK.20) | 
|  | */ | 
|  | INT16 WINAPI sendto16(SOCKET16 s, char *buf, INT16 len, INT16 flags, | 
|  | struct sockaddr *to, INT16 tolen) | 
|  | { | 
|  | return sendto( s, buf, len, flags, to, tolen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              setsockopt		(WINSOCK.21) | 
|  | */ | 
|  | INT16 WINAPI setsockopt16(SOCKET16 s, INT16 level, INT16 optname, | 
|  | char *optval, INT16 optlen) | 
|  | { | 
|  | if( !optval ) return SOCKET_ERROR; | 
|  | return setsockopt( s, (WORD)level, optname, optval, optlen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              shutdown		(WINSOCK.22) | 
|  | */ | 
|  | INT16 WINAPI shutdown16(SOCKET16 s, INT16 how) | 
|  | { | 
|  | return shutdown( s, how ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              socket		(WINSOCK.23) | 
|  | */ | 
|  | SOCKET16 WINAPI socket16(INT16 af, INT16 type, INT16 protocol) | 
|  | { | 
|  | return socket( af, type, protocol ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		gethostbyaddr		(WINSOCK.51) | 
|  | */ | 
|  | SEGPTR WINAPI gethostbyaddr16(const char *addr, INT16 len, INT16 type) | 
|  | { | 
|  | struct hostent *he; | 
|  |  | 
|  | if (!(he = gethostbyaddr( addr, len, type ))) return 0; | 
|  | return ws_hostent_32_to_16( he, 0, NULL ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		gethostbyname		(WINSOCK.52) | 
|  | */ | 
|  | SEGPTR WINAPI gethostbyname16(const char *name) | 
|  | { | 
|  | struct hostent *he; | 
|  |  | 
|  | if (!(he = gethostbyname( name ))) return 0; | 
|  | return ws_hostent_32_to_16( he, 0, NULL ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getprotobyname		(WINSOCK.53) | 
|  | */ | 
|  | SEGPTR WINAPI getprotobyname16(const char *name) | 
|  | { | 
|  | struct protoent *pe; | 
|  |  | 
|  | if (!(pe = getprotobyname( name ))) return 0; | 
|  | return ws_protoent_32_to_16( pe, 0, NULL ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getprotobynumber	(WINSOCK.54) | 
|  | */ | 
|  | SEGPTR WINAPI getprotobynumber16(INT16 number) | 
|  | { | 
|  | struct protoent *pe; | 
|  |  | 
|  | if (!(pe = getprotobynumber( number ))) return 0; | 
|  | return ws_protoent_32_to_16( pe, 0, NULL ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getservbyname		(WINSOCK.55) | 
|  | */ | 
|  | SEGPTR WINAPI getservbyname16(const char *name, const char *proto) | 
|  | { | 
|  | struct servent *se; | 
|  |  | 
|  | if (!(se = getservbyname( name, proto ))) return 0; | 
|  | return ws_servent_32_to_16( se, 0, NULL ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getservbyport		(WINSOCK.56) | 
|  | */ | 
|  | SEGPTR WINAPI getservbyport16(INT16 port, const char *proto) | 
|  | { | 
|  | struct servent *se; | 
|  |  | 
|  | if (!(se = getservbyport( port, proto ))) return 0; | 
|  | return ws_servent_32_to_16( se, 0, NULL ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              gethostname           (WINSOCK.57) | 
|  | */ | 
|  | INT16 WINAPI gethostname16(char *name, INT16 namelen) | 
|  | { | 
|  | extern int WINAPI gethostname(char *name, INT namelen); | 
|  | return gethostname(name, namelen); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAAsyncSelect		(WINSOCK.101) | 
|  | */ | 
|  | INT16 WINAPI WSAAsyncSelect16(SOCKET16 s, HWND16 hWnd, UINT16 wMsg, LONG lEvent) | 
|  | { | 
|  | return WSAAsyncSelect( s, HWND_32(hWnd), wMsg, lEvent ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetHostByAddr	(WINSOCK.102) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetHostByAddr16(HWND16 hWnd, UINT16 uMsg, LPCSTR addr, | 
|  | INT16 len, INT16 type, SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | struct async_query_gethostbyaddr *aq; | 
|  |  | 
|  | TRACE("hwnd %04x, msg %04x, addr %p[%i]\n", hWnd, uMsg, addr, len ); | 
|  |  | 
|  | if (!(aq = HeapAlloc( GetProcessHeap(), 0, sizeof(*aq) + len ))) | 
|  | { | 
|  | SetLastError( WSAEWOULDBLOCK ); | 
|  | return 0; | 
|  | } | 
|  | aq->host_addr = (char *)(aq + 1); | 
|  | aq->host_len  = len; | 
|  | aq->host_type = type; | 
|  | memcpy( aq->host_addr, addr, len ); | 
|  | return run_query( hWnd, uMsg, async_gethostbyaddr, &aq->query, sbuf, buflen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetHostByName	(WINSOCK.103) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetHostByName16(HWND16 hWnd, UINT16 uMsg, LPCSTR name, | 
|  | SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | struct async_query_gethostbyname *aq; | 
|  | unsigned int len = strlen(name) + 1; | 
|  |  | 
|  | TRACE("hwnd %04x, msg %04x, host %s, buffer %i\n", hWnd, uMsg, debugstr_a(name), buflen ); | 
|  |  | 
|  | if (!(aq = HeapAlloc( GetProcessHeap(), 0, sizeof(*aq) + len ))) | 
|  | { | 
|  | SetLastError( WSAEWOULDBLOCK ); | 
|  | return 0; | 
|  | } | 
|  | aq->host_name = (char *)(aq + 1); | 
|  | strcpy( aq->host_name, name ); | 
|  | return run_query( hWnd, uMsg, async_gethostbyname, &aq->query, sbuf, buflen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetProtoByNumber	(WINSOCK.104) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetProtoByNumber16(HWND16 hWnd,UINT16 uMsg,INT16 number, | 
|  | SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | struct async_query_getprotobynumber *aq; | 
|  |  | 
|  | TRACE("hwnd %04x, msg %04x, num %i\n", hWnd, uMsg, number ); | 
|  |  | 
|  | if (!(aq = HeapAlloc( GetProcessHeap(), 0, sizeof(*aq) ))) | 
|  | { | 
|  | SetLastError( WSAEWOULDBLOCK ); | 
|  | return 0; | 
|  | } | 
|  | aq->proto_number = number; | 
|  | return run_query( hWnd, uMsg, async_getprotobynumber, &aq->query, sbuf, buflen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetProtoByName	(WINSOCK.105) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetProtoByName16(HWND16 hWnd, UINT16 uMsg, LPCSTR name, | 
|  | SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | struct async_query_getprotobyname *aq; | 
|  | unsigned int len = strlen(name) + 1; | 
|  |  | 
|  | TRACE("hwnd %04x, msg %04x, proto %s, buffer %i\n", hWnd, uMsg, debugstr_a(name), buflen ); | 
|  |  | 
|  | if (!(aq = HeapAlloc( GetProcessHeap(), 0, sizeof(*aq) + len ))) | 
|  | { | 
|  | SetLastError( WSAEWOULDBLOCK ); | 
|  | return 0; | 
|  | } | 
|  | aq->proto_name = (char *)(aq + 1); | 
|  | strcpy( aq->proto_name, name ); | 
|  | return run_query( hWnd, uMsg, async_getprotobyname, &aq->query, sbuf, buflen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetServByPort	(WINSOCK.106) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetServByPort16(HWND16 hWnd, UINT16 uMsg, INT16 port, | 
|  | LPCSTR proto, SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | struct async_query_getservbyport *aq; | 
|  | unsigned int len = strlen(proto) + 1; | 
|  |  | 
|  | TRACE("hwnd %04x, msg %04x, port %i, proto %s\n", hWnd, uMsg, port, debugstr_a(proto)); | 
|  |  | 
|  | if (!(aq = HeapAlloc( GetProcessHeap(), 0, sizeof(*aq) + len ))) | 
|  | { | 
|  | SetLastError( WSAEWOULDBLOCK ); | 
|  | return 0; | 
|  | } | 
|  | aq->serv_proto = (char *)(aq + 1); | 
|  | aq->serv_port  = port; | 
|  | strcpy( aq->serv_proto, proto ); | 
|  | return run_query( hWnd, uMsg, async_getservbyport, &aq->query, sbuf, buflen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSAAsyncGetServByName	(WINSOCK.107) | 
|  | */ | 
|  | HANDLE16 WINAPI WSAAsyncGetServByName16(HWND16 hWnd, UINT16 uMsg, LPCSTR name, | 
|  | LPCSTR proto, SEGPTR sbuf, INT16 buflen) | 
|  | { | 
|  | struct async_query_getservbyname *aq; | 
|  | unsigned int len1 = strlen(name) + 1; | 
|  | unsigned int len2 = strlen(proto) + 1; | 
|  |  | 
|  | TRACE("hwnd %04x, msg %04x, name %s, proto %s\n", hWnd, uMsg, debugstr_a(name), debugstr_a(proto)); | 
|  |  | 
|  | if (!(aq = HeapAlloc( GetProcessHeap(), 0, sizeof(*aq) + len1 + len2 ))) | 
|  | { | 
|  | SetLastError( WSAEWOULDBLOCK ); | 
|  | return 0; | 
|  | } | 
|  | aq->serv_name  = (char *)(aq + 1); | 
|  | aq->serv_proto = aq->serv_name + len1; | 
|  | strcpy( aq->serv_name, name ); | 
|  | strcpy( aq->serv_proto, proto ); | 
|  | return run_query( hWnd, uMsg, async_getservbyname, &aq->query, sbuf, buflen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *       WSACancelAsyncRequest	(WINSOCK.108) | 
|  | */ | 
|  | INT16 WINAPI WSACancelAsyncRequest16(HANDLE16 hAsyncTaskHandle) | 
|  | { | 
|  | FIXME("(%04x),stub\n", hAsyncTaskHandle); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSASetBlockingHook		(WINSOCK.109) | 
|  | */ | 
|  | FARPROC16 WINAPI WSASetBlockingHook16(FARPROC16 lpBlockFunc) | 
|  | { | 
|  | /* FIXME: should deal with 16-bit proc */ | 
|  | return (FARPROC16)WSASetBlockingHook( (FARPROC)lpBlockFunc ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAUnhookBlockingHook	(WINSOCK.110) | 
|  | */ | 
|  | INT16 WINAPI WSAUnhookBlockingHook16(void) | 
|  | { | 
|  | return WSAUnhookBlockingHook(); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAGetLastError		(WINSOCK.111) | 
|  | */ | 
|  | INT WINAPI WSAGetLastError16(void) | 
|  | { | 
|  | return WSAGetLastError(); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSASetLastError		(WINSOCK.112) | 
|  | */ | 
|  | void WINAPI WSASetLastError16(INT16 iError) | 
|  | { | 
|  | WSASetLastError(iError); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSACancelBlockingCall		(WINSOCK.113) | 
|  | */ | 
|  | INT WINAPI WSACancelBlockingCall16(void) | 
|  | { | 
|  | return WSACancelBlockingCall(); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAIsBlocking			(WINSOCK.114) | 
|  | */ | 
|  | BOOL WINAPI WSAIsBlocking16(void) | 
|  | { | 
|  | return WSAIsBlocking(); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSAStartup			(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, LPWSADATA16 lpWSAData) | 
|  | { | 
|  | WSADATA data; | 
|  | INT ret = WSAStartup( wVersionRequested, &data ); | 
|  |  | 
|  | if (!ret) | 
|  | { | 
|  | lpWSAData->wVersion     = 0x0101; | 
|  | lpWSAData->wHighVersion = 0x0101; | 
|  | strcpy( lpWSAData->szDescription, data.szDescription ); | 
|  | strcpy( lpWSAData->szSystemStatus, data.szSystemStatus ); | 
|  | lpWSAData->iMaxSockets = data.iMaxSockets; | 
|  | lpWSAData->iMaxUdpDg = data.iMaxUdpDg; | 
|  | lpWSAData->lpVendorInfo = 0; | 
|  | num_startup++; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSACleanup			(WINSOCK.116) | 
|  | */ | 
|  | INT WINAPI WSACleanup16(void) | 
|  | { | 
|  | if (num_startup) | 
|  | { | 
|  | if (!--num_startup) | 
|  | { | 
|  | /* delete scratch buffers */ | 
|  | UnMapLS( he_buffer_seg ); | 
|  | UnMapLS( se_buffer_seg ); | 
|  | UnMapLS( pe_buffer_seg ); | 
|  | UnMapLS( dbuffer_seg ); | 
|  | he_buffer_seg = 0; | 
|  | se_buffer_seg = 0; | 
|  | pe_buffer_seg = 0; | 
|  | dbuffer_seg = 0; | 
|  | HeapFree( GetProcessHeap(), 0, he_buffer ); | 
|  | HeapFree( GetProcessHeap(), 0, se_buffer ); | 
|  | HeapFree( GetProcessHeap(), 0, pe_buffer ); | 
|  | he_buffer = NULL; | 
|  | se_buffer = NULL; | 
|  | pe_buffer = NULL; | 
|  | } | 
|  | } | 
|  | return WSACleanup(); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *	__WSAFDIsSet			(WINSOCK.151) | 
|  | */ | 
|  | INT16 WINAPI __WSAFDIsSet16(SOCKET16 s, ws_fd_set16 *set) | 
|  | { | 
|  | int i = set->fd_count; | 
|  |  | 
|  | TRACE("(%d,%p(%i))\n", s, set, i); | 
|  |  | 
|  | while (i--) | 
|  | if (set->fd_array[i] == s) return 1; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              WSARecvEx			(WINSOCK.1107) | 
|  | * | 
|  | * See description for WSARecvEx() | 
|  | */ | 
|  | INT16 WINAPI WSARecvEx16(SOCKET16 s, char *buf, INT16 len, INT16 *flags) | 
|  | { | 
|  | FIXME("(WSARecvEx16) partial packet return value not set\n"); | 
|  | return recv16(s, buf, len, *flags); | 
|  | } |