|  | /* | 
|  | * 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 "wine/port.h" | 
|  |  | 
|  | #include "winsock2.h" | 
|  | #include "wine/winbase16.h" | 
|  | #include "wine/winsock16.h" | 
|  | #include "wownt32.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(winsock); | 
|  |  | 
|  | 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 WS_fd_set *ws_fdset_16_to_32( const ws_fd_set16 *set16, WS_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 WS_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 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 WS_hostent* he ) | 
|  | { | 
|  | char *p; | 
|  | SEGPTR base; | 
|  | struct ws_hostent16 *p_to; | 
|  |  | 
|  | int size = (sizeof(*he) + | 
|  | strlen(he->h_name) + 1 + | 
|  | list_size(he->h_aliases, 0) + | 
|  | list_size(he->h_addr_list, he->h_length)); | 
|  |  | 
|  | 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 WS_protoent *pe ) | 
|  | { | 
|  | char *p; | 
|  | SEGPTR base; | 
|  | struct ws_protoent16 *p_to; | 
|  |  | 
|  | int size = (sizeof(*pe) + | 
|  | strlen(pe->p_name) + 1 + | 
|  | list_size(pe->p_aliases, 0)); | 
|  |  | 
|  | 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 WS_servent *se ) | 
|  | { | 
|  | char *p; | 
|  | SEGPTR base; | 
|  | struct ws_servent16 *p_to; | 
|  |  | 
|  | int size = (sizeof(*se) + | 
|  | strlen(se->s_proto) + 1 + | 
|  | strlen(se->s_name) + 1 + | 
|  | list_size(se->s_aliases, 0)); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              accept		(WINSOCK.1) | 
|  | */ | 
|  | SOCKET16 WINAPI accept16(SOCKET16 s, struct WS_sockaddr* addr, INT16* addrlen16 ) | 
|  | { | 
|  | INT addrlen32 = addrlen16 ? *addrlen16 : 0; | 
|  | SOCKET retSocket = WS_accept( s, addr, &addrlen32 ); | 
|  | if( addrlen16 ) *addrlen16 = addrlen32; | 
|  | return retSocket; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              bind			(WINSOCK.2) | 
|  | */ | 
|  | INT16 WINAPI bind16(SOCKET16 s, struct WS_sockaddr *name, INT16 namelen) | 
|  | { | 
|  | return WS_bind( s, name, namelen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              closesocket           (WINSOCK.3) | 
|  | */ | 
|  | INT16 WINAPI closesocket16(SOCKET16 s) | 
|  | { | 
|  | return WS_closesocket(s); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              connect               (WINSOCK.4) | 
|  | */ | 
|  | INT16 WINAPI connect16(SOCKET16 s, struct WS_sockaddr *name, INT16 namelen) | 
|  | { | 
|  | return WS_connect( s, name, namelen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              getpeername		(WINSOCK.5) | 
|  | */ | 
|  | INT16 WINAPI getpeername16(SOCKET16 s, struct WS_sockaddr *name, INT16 *namelen16) | 
|  | { | 
|  | INT namelen32 = *namelen16; | 
|  | INT retVal = WS_getpeername( s, name, &namelen32 ); | 
|  | *namelen16 = namelen32; | 
|  | return retVal; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              getsockname		(WINSOCK.6) | 
|  | */ | 
|  | INT16 WINAPI getsockname16(SOCKET16 s, struct WS_sockaddr *name, INT16 *namelen16) | 
|  | { | 
|  | INT retVal; | 
|  |  | 
|  | if( namelen16 ) | 
|  | { | 
|  | INT namelen32 = *namelen16; | 
|  | retVal = WS_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 = WS_getsockopt( s, (WORD)level, optname, optval, p ); | 
|  | if( optlen ) *optlen = optlen32; | 
|  | return retVal; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		inet_ntoa		(WINSOCK.11) | 
|  | */ | 
|  | SEGPTR WINAPI inet_ntoa16(struct WS_in_addr in) | 
|  | { | 
|  | char* retVal; | 
|  | if (!(retVal = WS_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, ULONG *argp) | 
|  | { | 
|  | return WS_ioctlsocket( s, cmd, argp ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              listen		(WINSOCK.13) | 
|  | */ | 
|  | INT16 WINAPI listen16(SOCKET16 s, INT16 backlog) | 
|  | { | 
|  | return WS_listen( s, backlog ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              recv			(WINSOCK.16) | 
|  | */ | 
|  | INT16 WINAPI recv16(SOCKET16 s, char *buf, INT16 len, INT16 flags) | 
|  | { | 
|  | return WS_recv( s, buf, len, flags ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              recvfrom		(WINSOCK.17) | 
|  | */ | 
|  | INT16 WINAPI recvfrom16(SOCKET16 s, char *buf, INT16 len, INT16 flags, | 
|  | struct WS_sockaddr *from, INT16 *fromlen16) | 
|  | { | 
|  | if (fromlen16) | 
|  | { | 
|  | INT fromlen32 = *fromlen16; | 
|  | INT retVal = WS_recvfrom( s, buf, len, flags, from, &fromlen32 ); | 
|  | *fromlen16 = fromlen32; | 
|  | return retVal; | 
|  | } | 
|  | else return WS_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 WS_timeval* timeout) | 
|  | { | 
|  | WS_fd_set read_set, write_set, except_set; | 
|  | WS_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 = WS_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 WS_send( s, buf, len, flags ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              sendto		(WINSOCK.20) | 
|  | */ | 
|  | INT16 WINAPI sendto16(SOCKET16 s, char *buf, INT16 len, INT16 flags, | 
|  | struct WS_sockaddr *to, INT16 tolen) | 
|  | { | 
|  | return WS_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 WS_setsockopt( s, (WORD)level, optname, optval, optlen ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              shutdown		(WINSOCK.22) | 
|  | */ | 
|  | INT16 WINAPI shutdown16(SOCKET16 s, INT16 how) | 
|  | { | 
|  | return WS_shutdown( s, how ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              socket		(WINSOCK.23) | 
|  | */ | 
|  | SOCKET16 WINAPI socket16(INT16 af, INT16 type, INT16 protocol) | 
|  | { | 
|  | return WS_socket( af, type, protocol ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		gethostbyaddr		(WINSOCK.51) | 
|  | */ | 
|  | SEGPTR WINAPI gethostbyaddr16(const char *addr, INT16 len, INT16 type) | 
|  | { | 
|  | struct WS_hostent *he; | 
|  |  | 
|  | if (!(he = WS_gethostbyaddr( addr, len, type ))) return 0; | 
|  | return ws_hostent_32_to_16( he ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		gethostbyname		(WINSOCK.52) | 
|  | */ | 
|  | SEGPTR WINAPI gethostbyname16(const char *name) | 
|  | { | 
|  | struct WS_hostent *he; | 
|  |  | 
|  | if (!(he = WS_gethostbyname( name ))) return 0; | 
|  | return ws_hostent_32_to_16( he ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getprotobyname		(WINSOCK.53) | 
|  | */ | 
|  | SEGPTR WINAPI getprotobyname16(const char *name) | 
|  | { | 
|  | struct WS_protoent *pe; | 
|  |  | 
|  | if (!(pe = WS_getprotobyname( name ))) return 0; | 
|  | return ws_protoent_32_to_16( pe ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getprotobynumber	(WINSOCK.54) | 
|  | */ | 
|  | SEGPTR WINAPI getprotobynumber16(INT16 number) | 
|  | { | 
|  | struct WS_protoent *pe; | 
|  |  | 
|  | if (!(pe = WS_getprotobynumber( number ))) return 0; | 
|  | return ws_protoent_32_to_16( pe ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getservbyname		(WINSOCK.55) | 
|  | */ | 
|  | SEGPTR WINAPI getservbyname16(const char *name, const char *proto) | 
|  | { | 
|  | struct WS_servent *se; | 
|  |  | 
|  | if (!(se = WS_getservbyname( name, proto ))) return 0; | 
|  | return ws_servent_32_to_16( se ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *		getservbyport		(WINSOCK.56) | 
|  | */ | 
|  | SEGPTR WINAPI getservbyport16(INT16 port, const char *proto) | 
|  | { | 
|  | struct WS_servent *se; | 
|  |  | 
|  | if (!(se = WS_getservbyport( port, proto ))) return 0; | 
|  | return ws_servent_32_to_16( se ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *              gethostname           (WINSOCK.57) | 
|  | */ | 
|  | INT16 WINAPI gethostname16(char *name, INT16 namelen) | 
|  | { | 
|  | return WS_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 ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      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(); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      WSASetLastError		(WINSOCK.112) | 
|  | */ | 
|  | void WINAPI WSASetLastError16(INT16 iError) | 
|  | { | 
|  | WSASetLastError(iError); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *      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); | 
|  | } |