/* * 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); }