| /* | |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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( he_buffer ); | |
| return pe_buffer_seg; | |
| } | |
| /* duplicate hostent entry | |
| * and handle all Win16/Win32 dependent things (struct size, ...) *correctly*. | |
| * Dito 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, 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, 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); | |
| } |