/* * 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. * * TODO: 32-bit asynchronous services. */ #include #include #include #include #include #include #if defined(__svr4__) #include #include #include #endif #if defined(__EMX__) #include #include #endif #include #include #include #include #include #include #include #include #include #include "windows.h" #include "winnt.h" #include "heap.h" #include "ldt.h" #include "task.h" #include "message.h" #include "winsock.h" #include "miscemu.h" #include "stddebug.h" #include "debug.h" #define dump_sockaddr(a) \ fprintf(stderr, "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 */ extern int h_errno; static HANDLE32 _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 INT32 _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 _check_ws(LPWSINFO pwsi, ws_socket* pws); static int _check_buffer(LPWSINFO pwsi, int size); extern void EVENT_AddIO( int fd, unsigned flag ); extern void EVENT_DeleteIO( int fd, unsigned flag ); /*********************************************************************** * convert_sockopt() * * Converts socket flags from Windows format. */ static void convert_sockopt(INT32 *level, INT32 *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 fprintf(stderr, "convert_sockopt() unknown optname %d\n", *optname); break; case WS_IPPROTO_TCP: *optname = IPPROTO_TCP; } } /* ----------------------------------- 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 ) fprintf(stderr,"loose wsi struct! pwsi=0x%08x, task=0x%04x\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 void fd_set_normalize(fd_set* fds, LPWSINFO pwsi, ws_fd_set* ws, int* highfd) { /* translate Winsock fd set into the normal fd set */ FD_ZERO(fds); if( ws ) { int i; ws_socket* pws; for( i = 0; i < (ws->fd_count) ; i++ ) { pws = (ws_socket*)WS_HANDLE2PTR(ws->fd_array[i]); if( _check_ws(pwsi, pws) ) { if( pws->fd > *highfd ) *highfd = pws->fd; FD_SET(pws->fd, fds); } } } } /* * Note weirdness here: sockets with errors belong in exceptfds, but * are given to us in readfds or writefds, so move them to exceptfds if * there is an error. Note that this means that exceptfds may have mysterious * sockets set in it that the program never asked for. */ __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) dprintf_winsock(stddeb, "error: %d\n", optval); return optval != 0; } static void fd_set_update(LPWSINFO pwsi, fd_set* fds, ws_fd_set* ws, fd_set *errorfds) { if( ws ) { int i, j, count = ws->fd_count; for( i = 0, j = 0; i < count; i++ ) { ws_socket *pws = (ws_socket*)WS_HANDLE2PTR(ws->fd_array[i]); int fd = pws->fd; if( _check_ws(pwsi, pws) && FD_ISSET(fd, fds) ) { /* if error, move to errorfds */ if (errorfds && (FD_ISSET(fd, errorfds) || sock_error_p(fd))) FD_SET(fd, errorfds); else ws->fd_array[j++] = ws->fd_array[i]; } } ws->fd_count = j; dprintf_winsock(stddeb, "\n"); } return; } 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_THREAD, WS_MAX_UDP_DATAGRAM, (SEGPTR)NULL }; HTASK16 tid = GetCurrentTask(); LPWSINFO pwsi; dprintf_winsock(stddeb, "WSAStartup: 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)) ) { fprintf(stderr,"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_THREAD; i++ ) { pwsi->sock[i].fd = -1; pwsi->sock[i].flags = i + 1; } pwsi->sock[WS_MAX_SOCKETS_PER_THREAD - 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)); dprintf_winsock(stddeb, "WSAStartup: succeeded\n"); return 0; } /*********************************************************************** * WSAStartup32() (WSOCK32.115) */ INT32 WINAPI WSAStartup32(UINT32 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 ); } INT32 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 ); if( pTask ) pTask->pwsi = NULL; 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 ) dprintf_winsock(stddeb,"\tinside blocking call!\n"); /* FIXME: aop_control() doesn't decrement pwsi->num_async_rq * * if( pwsi->num_async_rq ) * dprintf_winsock(stddeb,"\thave %i outstanding async ops!\n", pwsi->num_async_rq ); */ for(i = 0, j = 0, n = 0; i < WS_MAX_SOCKETS_PER_THREAD; 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 ) dprintf_winsock(stddeb,"\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); memset( pwsi, 0, sizeof(WSINFO) ); WS_FREE(pwsi); return 0; } INT32 WINAPI WSACleanup(void) { HTASK16 hTask = GetCurrentTask(); dprintf_winsock(stddeb, "WSACleanup(%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) */ INT32 WINAPI WSAGetLastError(void) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); INT16 ret; dprintf_winsock(stddeb, "WSAGetLastError(%08x)", (unsigned)pwsi); ret = (pwsi) ? pwsi->err : WSANOTINITIALISED; dprintf_winsock(stddeb, " = %i\n", (int)ret); return ret; } /*********************************************************************** * WSASetLastError32() (WSOCK32.112) */ void WINAPI WSASetLastError32(INT32 iError) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WSASetLastError(%08x): %d\n", (unsigned)pwsi, (int)iError); if( pwsi ) pwsi->err = iError; } /*********************************************************************** * WSASetLastError16() (WINSOCK.112) */ void WINAPI WSASetLastError16(INT16 iError) { WSASetLastError32(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; } int _check_buffer(LPWSINFO pwsi, int size) { if( pwsi->buffer && pwsi->buflen >= size ) return 1; else SEGPTR_FREE(pwsi->buffer); pwsi->buffer = (char*)SEGPTR_ALLOC((pwsi->buflen = size)); return (pwsi->buffer != NULL); } /* ----------------------------------- i/o APIs */ /*********************************************************************** * accept() (WSOCK32.1) */ SOCKET32 WINAPI WINSOCK_accept32(SOCKET32 s, struct sockaddr *addr, INT32 *addrlen32) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR((SOCKET16)s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_ACCEPT(%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 = (SOCKET32)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 ); } return s; } else pwsi->err = WSAENOBUFS; } else pwsi->err = wsaErrno(); } return INVALID_SOCKET32; } /*********************************************************************** * accept() (WINSOCK.1) */ SOCKET16 WINAPI WINSOCK_accept16(SOCKET16 s, struct sockaddr* addr, INT16* addrlen16 ) { INT32 addrlen32 = *addrlen16; SOCKET32 retSocket = WINSOCK_accept32( s, addr, &addrlen32 ); *addrlen16 = (INT16)addrlen32; return (SOCKET16)retSocket; } /*********************************************************************** * bind() (WSOCK32.2) */ INT32 WINAPI WINSOCK_bind32(SOCKET32 s, struct sockaddr *name, INT32 namelen) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_BIND(%08x): socket %04x, ptr %8x, length %d\n", (unsigned)pwsi, s, (int) name, namelen); #if 0 dump_sockaddr(name); #endif if ( _check_ws(pwsi, pws) ) if ( namelen >= sizeof(*name) ) if ( ((struct sockaddr_in *)name)->sin_family == AF_INET ) if ( bind(pws->fd, name, namelen) < 0 ) { int loc_errno = errno; dprintf_winsock(stddeb,"\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 return 0; /* success */ else pwsi->err = WSAEAFNOSUPPORT; else pwsi->err = WSAEFAULT; return SOCKET_ERROR; } /*********************************************************************** * bind() (WINSOCK.2) */ INT16 WINAPI WINSOCK_bind16(SOCKET16 s, struct sockaddr *name, INT16 namelen) { return (INT16)WINSOCK_bind32( s, name, namelen ); } /*********************************************************************** * closesocket() (WSOCK32.3) */ INT32 WINAPI WINSOCK_closesocket32(SOCKET32 s) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_CLOSE(%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_closesocket32(s); } /*********************************************************************** * connect() (WSOCK32.4) */ INT32 WINAPI WINSOCK_connect32(SOCKET32 s, struct sockaddr *name, INT32 namelen) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_CONNECT(%08x): socket %04x, ptr %8x, length %d\n", (unsigned)pwsi, s, (int) name, namelen); #if 0 dump_sockaddr(name); #endif if( _check_ws(pwsi, pws) ) { if (connect(pws->fd, name, namelen) == 0) { pws->flags &= ~(WS_FD_INACTIVE | WS_FD_CONNECT); if( pws->psop && pws->flags & WS_FD_CONNECT ) { 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; } } return 0; } pwsi->err = (errno == EINPROGRESS) ? WSAEWOULDBLOCK : wsaErrno(); } return SOCKET_ERROR; } /*********************************************************************** * connect() (WINSOCK.4) */ INT16 WINAPI WINSOCK_connect16(SOCKET16 s, struct sockaddr *name, INT16 namelen) { return (INT16)WINSOCK_connect32( s, name, namelen ); } /*********************************************************************** * getpeername() (WSOCK32.5) */ INT32 WINAPI WINSOCK_getpeername32(SOCKET32 s, struct sockaddr *name, INT32 *namelen) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GETPEERNAME(%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) return 0; pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return SOCKET_ERROR; } /*********************************************************************** * getpeername() (WINSOCK.5) */ INT16 WINAPI WINSOCK_getpeername16(SOCKET16 s, struct sockaddr *name, INT16 *namelen16) { INT32 namelen32 = *namelen16; INT32 retVal = WINSOCK_getpeername32( s, name, &namelen32 ); #if 0 dump_sockaddr(name); #endif *namelen16 = namelen32; return (INT16)retVal; } /*********************************************************************** * getsockname() (WSOCK32.6) */ INT32 WINAPI WINSOCK_getsockname32(SOCKET32 s, struct sockaddr *name, INT32 *namelen) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GETSOCKNAME(%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) return 0; pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return SOCKET_ERROR; } /*********************************************************************** * getsockname() (WINSOCK.6) */ INT16 WINAPI WINSOCK_getsockname16(SOCKET16 s, struct sockaddr *name, INT16 *namelen16) { INT32 namelen32 = *namelen16; INT32 retVal = WINSOCK_getsockname32( s, name, &namelen32 ); *namelen16 = namelen32; return (INT16)retVal; } /*********************************************************************** * getsockopt() (WSOCK32.7) */ INT32 WINAPI WINSOCK_getsockopt32(SOCKET32 s, INT32 level, INT32 optname, char *optval, INT32 *optlen) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GETSOCKOPT(%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) { INT32 optlen32 = *optlen; INT32 retVal = WINSOCK_getsockopt32( s, level, optname, optval, &optlen32 ); *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) */ 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) */ SEGPTR 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 (SEGPTR)NULL; } strncpy(pwsi->dbuffer, s, 32 ); return SEGPTR_GET(pwsi->dbuffer); } pwsi->err = wsaErrno(); } return (SEGPTR)NULL; } /*********************************************************************** * ioctlsocket() (WSOCK32.12) */ INT32 WINAPI WINSOCK_ioctlsocket32(SOCKET32 s, UINT32 cmd, UINT32 *argp) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_IOCTL(%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): fprintf(stderr,"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 */ dprintf_winsock(stddeb,"\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, UINT32 cmd, UINT32 *argp) { return (INT16)WINSOCK_ioctlsocket32( s, cmd, argp ); } /*********************************************************************** * listen() (WSOCK32.13) */ INT32 WINAPI WINSOCK_listen32(SOCKET32 s, INT32 backlog) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_LISTEN(%08x): socket %04x, backlog %d\n", (unsigned)pwsi, s, backlog); if( _check_ws(pwsi, pws) ) { if( !pws->psop ) { int fd_flags = fcntl(pws->fd, F_GETFL, 0); if( !(fd_flags & O_NONBLOCK) ) pws->flags |= WS_FD_ACCEPT; } if (listen(pws->fd, backlog) == 0) 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_listen32( s, backlog ); } /*********************************************************************** * recv() (WSOCK32.16) */ INT32 WINAPI WINSOCK_recv32(SOCKET32 s, char *buf, INT32 len, INT32 flags) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_RECV(%08x): socket %04x, buf %8x, len %d, flags %d", (unsigned)pwsi, s, (unsigned)buf, len, flags); if( _check_ws(pwsi, pws) ) { INT32 length; if ((length = recv(pws->fd, buf, len, flags)) >= 0) { dprintf_winsock(stddeb, " -> %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; dprintf_winsock(stddeb, " -> ERROR\n"); return SOCKET_ERROR; } /*********************************************************************** * recv() (WINSOCK.16) */ INT16 WINAPI WINSOCK_recv16(SOCKET16 s, char *buf, INT16 len, INT16 flags) { return (INT16)WINSOCK_recv32( s, buf, len, flags ); } /*********************************************************************** * recvfrom() (WSOCK32.17) */ INT32 WINAPI WINSOCK_recvfrom32(SOCKET32 s, char *buf, INT32 len, INT32 flags, struct sockaddr *from, INT32 *fromlen32) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_RECVFROM(%08x): socket %04x, ptr %08x, len %d, flags %d", (unsigned)pwsi, s, (unsigned)buf, len, flags); if( _check_ws(pwsi, pws) ) { int length; if ((length = recvfrom(pws->fd, buf, len, flags, from, fromlen32)) >= 0) { dprintf_winsock(stddeb, " -> %i bytes\n", length); if( pws->psop && (pws->flags & (WS_FD_READ | WS_FD_CLOSE)) ) EVENT_AddIO( pws->fd, EVENT_IO_READ ); /* reenabler */ return (INT16)length; } pwsi->err = wsaErrno(); } else if( pwsi ) pwsi->err = WSAENOTSOCK; dprintf_winsock(stddeb, " -> ERROR\n"); return SOCKET_ERROR; } /*********************************************************************** * recvfrom() (WINSOCK.17) */ INT16 WINAPI WINSOCK_recvfrom16(SOCKET16 s, char *buf, INT16 len, INT16 flags, struct sockaddr *from, INT16 *fromlen16) { INT32 fromlen32 = *fromlen16; INT32 retVal = WINSOCK_recvfrom32( s, buf, len, flags, from, &fromlen32 ); *fromlen16 = fromlen32; return (INT16)retVal; } /*********************************************************************** * select() (WINSOCK.18) */ INT16 WINAPI WINSOCK_select16(INT16 nfds, ws_fd_set *ws_readfds, ws_fd_set *ws_writefds, ws_fd_set *ws_exceptfds, struct timeval *timeout) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_SELECT(%08x): nfds %d (ignored), read %8x, write %8x, excp %8x\n", (unsigned) pwsi, nfds, (unsigned) ws_readfds, (unsigned) ws_writefds, (unsigned) ws_exceptfds); if( pwsi ) { int highfd = 0; fd_set readfds, writefds, exceptfds, errorfds; fd_set_normalize(&readfds, pwsi, ws_readfds, &highfd); fd_set_normalize(&writefds, pwsi, ws_writefds, &highfd); fd_set_normalize(&exceptfds, pwsi, ws_exceptfds, &highfd); FD_ZERO(&errorfds); if( (highfd = select(highfd + 1, &readfds, &writefds, &exceptfds, timeout)) >= 0 ) { if( highfd ) { fd_set_update(pwsi, &readfds, ws_readfds, &errorfds); fd_set_update(pwsi, &writefds, ws_writefds, &errorfds); /* update exception set (see "weirdness" comment in the * beginning of the file). */ if (ws_exceptfds) { int i, j, count = ws_exceptfds->fd_count; for (i = j = 0; i < count; i++) { ws_socket *pws = (ws_socket *)WS_HANDLE2PTR(ws_exceptfds->fd_array[i]); if( _check_ws(pwsi, pws) && (FD_ISSET(pws->fd, &exceptfds) || FD_ISSET(pws->fd, &errorfds)) ) ws_exceptfds->fd_array[j++] = ws_exceptfds->fd_array[i]; } ws_exceptfds->fd_count = j; } } return highfd; } pwsi->err = wsaErrno(); } return SOCKET_ERROR; } /*********************************************************************** * select() (WSOCK32.18) */ INT32 WINAPI WINSOCK_select32(INT32 nfds, ws_fd_set *ws_readfds, ws_fd_set *ws_writefds, ws_fd_set *ws_exceptfds, struct timeval *timeout) { /* struct timeval is the same for both 32- and 16-bit code */ return WINSOCK_select16( (INT16)nfds, ws_readfds, ws_writefds, ws_exceptfds, timeout ); } /*********************************************************************** * send() (WSOCK32.19) */ INT32 WINAPI WINSOCK_send32(SOCKET32 s, char *buf, INT32 len, INT32 flags) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_SEND(%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_send32( s, buf, len, flags ); } /*********************************************************************** * sendto() (WSOCK32.20) */ INT32 WINAPI WINSOCK_sendto32(SOCKET32 s, char *buf, INT32 len, INT32 flags, struct sockaddr *to, INT32 tolen) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_SENDTO(%08x): socket %04x, ptr %08x, length %d, flags %d\n", (unsigned)pwsi, s, (unsigned) buf, len, flags); if( _check_ws(pwsi, pws) ) { INT32 length; 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 return length; } else if( pwsi ) pwsi->err = WSAENOTSOCK; 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_sendto32( s, buf, len, flags, to, tolen ); } /*********************************************************************** * setsockopt() (WSOCK32.21) */ INT32 WINAPI WINSOCK_setsockopt32(SOCKET16 s, INT32 level, INT32 optname, char *optval, INT32 optlen) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_SETSOCKOPT(%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) ) { convert_sockopt(&level, &optname); 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) { INT32 linger32[2]; if( optname == SO_LINGER ) { INT16* ptr = (INT16*)optval; linger32[0] = ptr[0]; linger32[1] = ptr[1]; optval = (char*)&linger32; optlen = sizeof(linger32); } return (INT16)WINSOCK_setsockopt32( s, level, optname, optval, optlen ); } /*********************************************************************** * shutdown() (WSOCK32.22) */ INT32 WINAPI WINSOCK_shutdown32(SOCKET32 s, INT32 how) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_SHUTDOWN(%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); break; case 1: /* drop sends */ if( pws->flags & WS_FD_WRITE ) EVENT_DeleteIO( pws->fd, EVENT_IO_WRITE ); pws->flags &= ~WS_FD_WRITE; break; case 2: /* drop all */ default: WSAAsyncSelect( s, 0, 0, 0 ); break; } if (shutdown(pws->fd, how) == 0) { if( how > 1 ) { pws->flags &= ~WS_FD_CONNECTED; 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_shutdown32( s, how ); } /*********************************************************************** * socket() (WSOCK32.23) */ SOCKET32 WINAPI WINSOCK_socket32(INT32 af, INT32 type, INT32 protocol) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_SOCKET(%08x): af=%d type=%d protocol=%d\n", (unsigned)pwsi, af, type, protocol); if( pwsi ) { int sock; /* check the socket family */ switch(af) { case AF_INET: case AF_UNSPEC: break; default: pwsi->err = WSAEAFNOSUPPORT; return INVALID_SOCKET32; } /* check the socket type */ switch(type) { case SOCK_STREAM: case SOCK_DGRAM: case SOCK_RAW: break; default: pwsi->err = WSAESOCKTNOSUPPORT; return INVALID_SOCKET32; } /* check the protocol type */ if ( protocol < 0 ) /* don't support negative values */ { pwsi->err = WSAEPROTONOSUPPORT; return INVALID_SOCKET32; } 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_SOCKET32; } if ((sock = socket(af, type, protocol)) >= 0) { ws_socket* pnew = wsi_alloc_socket(pwsi, sock); dprintf_winsock(stddeb,"\tcreated %04x (handle %i)\n", sock, (UINT16)WS_PTR2HANDLE(pnew)); if( pnew ) return (SOCKET16)WS_PTR2HANDLE(pnew); close(sock); pwsi->err = WSAENOBUFS; return INVALID_SOCKET32; } if (errno == EPERM) /* raw socket denied */ { fprintf(stderr, "WS_SOCKET: not enough privileges\n"); pwsi->err = WSAESOCKTNOSUPPORT; } else pwsi->err = wsaErrno(); } dprintf_winsock(stddeb, "\t\tfailed!\n"); return INVALID_SOCKET32; } /*********************************************************************** * socket() (WINSOCK.23) */ SOCKET16 WINAPI WINSOCK_socket16(INT16 af, INT16 type, INT16 protocol) { return (SOCKET16)WINSOCK_socket32( af, type, protocol ); } /* ----------------------------------- DNS services * * IMPORTANT: 16-bit API structures have SEGPTR pointers inside them. * Also, we have to use wsock32 stubs to convert error codes from Unix * to WSA, hence no direct mapping in if1632/wsock32.spec. * * FIXME: Win32 may need "short" h_addrtype and h_length in * ...ent structures. If so, use WS_dup_...(pwsi, ..., 0) to * convert. */ static char* NULL_STRING = "NULL"; /*********************************************************************** * gethostbyaddr() (WINSOCK.51) * * struct WIN_hostent * */ SEGPTR WINAPI WINSOCK_gethostbyaddr16(const char *addr, INT16 len, INT16 type) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetHostByAddr16(%08x): ptr %8x, len %d, type %d\n", (unsigned)pwsi, (unsigned) addr, len, type); if( pwsi ) { struct hostent* host = gethostbyaddr(addr, len, type); if( host ) if( WS_dup_he(pwsi, host, WS_DUP_SEGPTR) ) return SEGPTR_GET(pwsi->buffer); else pwsi->err = WSAENOBUFS; else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return (SEGPTR)NULL; } /*********************************************************************** * gethostbyaddr() (WSOCK32.51) */ struct hostent* WINAPI WINSOCK_gethostbyaddr32(const char *addr, INT32 len, INT32 type) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetHostByAddr32(%08x): ptr %8x, len %d, type %d\n", (unsigned)pwsi, (unsigned) addr, len, type); if( pwsi ) { struct hostent* host = gethostbyaddr( addr, len, type ); if( host ) return host; pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return NULL; } /*********************************************************************** * gethostbyname() (WINSOCK.52) * * struct WIN_hostent * */ SEGPTR WINAPI WINSOCK_gethostbyname16(const char *name) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetHostByName16(%08x): %s\n", (unsigned)pwsi, (name)?name:"NULL"); if( pwsi ) { struct hostent* host; if( (host = gethostbyname(name)) != NULL ) if( WS_dup_he(pwsi, host, WS_DUP_SEGPTR) ) return SEGPTR_GET(pwsi->buffer); else pwsi->err = WSAENOBUFS; else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return (SEGPTR)NULL; } /*********************************************************************** * gethostbyname() (WSOCK32,52) */ struct hostent* WINAPI WINSOCK_gethostbyname32(const char* name) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetHostByName32(%08x): %s\n", (unsigned)pwsi, (name)?name:"NULL"); if( pwsi ) { struct hostent* host = gethostbyname( name ); if( host ) return host; pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return NULL; } /*********************************************************************** * gethostname() (WSOCK32.57) */ INT32 WINAPI WINSOCK_gethostname32(char *name, INT32 namelen) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetHostName(%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_gethostname32(name, namelen); } /*********************************************************************** * getprotobyname() (WINSOCK.53) * * struct WIN_protoent * */ SEGPTR WINAPI WINSOCK_getprotobyname16(char *name) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetProtoByName16(%08x): %s\n", (unsigned)pwsi, (name)?name:NULL_STRING); if( pwsi ) { struct protoent* proto; if( (proto = getprotobyname(name)) != NULL ) if( WS_dup_pe(pwsi, proto, WS_DUP_SEGPTR) ) return SEGPTR_GET(pwsi->buffer); else pwsi->err = WSAENOBUFS; else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return (SEGPTR)NULL; } /*********************************************************************** * getprotobyname() (WSOCK32.53) */ struct protoent* WINAPI WINSOCK_getprotobyname32(char* name) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetProtoByName32(%08x): %s\n", (unsigned)pwsi, (name)?name:NULL_STRING); if( pwsi ) { struct protoent* proto; if( (proto = getprotobyname(name)) != NULL ) return proto; pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return NULL; } /*********************************************************************** * getprotobynumber() (WINSOCK.54) * * struct WIN_protoent * */ SEGPTR WINAPI WINSOCK_getprotobynumber16(INT16 number) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetProtoByNumber16(%08x): %i\n", (unsigned)pwsi, number); if( pwsi ) { struct protoent* proto; if( (proto = getprotobynumber(number)) != NULL ) if( WS_dup_pe(pwsi, proto, WS_DUP_SEGPTR) ) return SEGPTR_GET(pwsi->buffer); else pwsi->err = WSAENOBUFS; else pwsi->err = WSANO_DATA; } return (SEGPTR)NULL; } /*********************************************************************** * getprotobynumber() (WSOCK32.54) */ struct protoent* WINAPI WINSOCK_getprotobynumber32(INT32 number) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetProtoByNumber32(%08x): %i\n", (unsigned)pwsi, number); if( pwsi ) { struct protoent* proto; if( (proto = getprotobynumber(number)) != NULL ) return proto; pwsi->err = WSANO_DATA; } return NULL; } /*********************************************************************** * getservbyname() (WINSOCK.55) * * struct WIN_servent * */ SEGPTR WINAPI WINSOCK_getservbyname16(const char *name, const char *proto) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetServByName16(%08x): '%s', '%s'\n", (unsigned)pwsi, (name)?name:NULL_STRING, (proto)?proto:NULL_STRING); if( pwsi ) { struct servent* serv; if( (serv = getservbyname(name, proto)) != NULL ) if( WS_dup_se(pwsi, serv, WS_DUP_SEGPTR) ) return SEGPTR_GET(pwsi->buffer); else pwsi->err = WSAENOBUFS; else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return (SEGPTR)NULL; } /*********************************************************************** * getservbyname() (WSOCK32.55) */ struct servent* WINAPI WINSOCK_getservbyname32(const char *name, const char *proto) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetServByName32(%08x): '%s', '%s'\n", (unsigned)pwsi, (name)?name:NULL_STRING, (proto)?proto:NULL_STRING); if( pwsi ) { struct servent* serv; if( (serv = getservbyname(name, proto)) != NULL ) return serv; pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return NULL; } /*********************************************************************** * getservbyport() (WINSOCK.56) * * struct WIN_servent * */ SEGPTR WINAPI WINSOCK_getservbyport16(INT16 port, const char *proto) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetServByPort16(%08x): %i, '%s'\n", (unsigned)pwsi, (int)port, (proto)?proto:NULL_STRING); if( pwsi ) { struct servent* serv; if( (serv = getservbyport(port, proto)) != NULL ) if( WS_dup_se(pwsi, serv, WS_DUP_SEGPTR) ) return SEGPTR_GET(pwsi->buffer); else pwsi->err = WSAENOBUFS; else pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return (SEGPTR)NULL; } /*********************************************************************** * getservbyport() (WSOCK32.56) */ struct servent* WINAPI WINSOCK_getservbyport32(INT32 port, const char *proto) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_GetServByPort32(%08x): %i, '%s'\n", (unsigned)pwsi, (int)port, (proto)?proto:NULL_STRING); if( pwsi ) { struct servent* serv; if( (serv = getservbyport(port, proto)) != NULL ) return serv; pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); } return NULL; } /* ------------------------------------- Windows sockets extensions -- * * * * ------------------------------------------------------------------- */ /*********************************************************************** * Asynchronous DNS services */ /* winsock_dns.c */ extern HANDLE16 __WSAsyncDBQuery(LPWSINFO pwsi, HWND16 hWnd, UINT16 uMsg, INT16 type, LPCSTR init, INT16 len, LPCSTR proto, SEGPTR sbuf, INT16 buflen, UINT32 flag); /*********************************************************************** * WSAAsyncGetHostByAddr() (WINSOCK.102) */ HANDLE16 WINAPI WSAAsyncGetHostByAddr(HWND16 hWnd, UINT16 uMsg, LPCSTR addr, INT16 len, INT16 type, SEGPTR sbuf, INT16 buflen) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_AsyncGetHostByAddr(%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, sbuf, buflen, WSMSG_ASYNC_HOSTBYADDR ); return 0; } /*********************************************************************** * WSAAsyncGetHostByName() (WINSOCK.103) */ HANDLE16 WINAPI WSAAsyncGetHostByName(HWND16 hWnd, UINT16 uMsg, LPCSTR name, SEGPTR sbuf, INT16 buflen) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_AsyncGetHostByName(%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, sbuf, buflen, WSMSG_ASYNC_HOSTBYNAME ); return 0; } /*********************************************************************** * WSAAsyncGetProtoByName() (WINSOCK.105) */ HANDLE16 WINAPI WSAAsyncGetProtoByName(HWND16 hWnd, UINT16 uMsg, LPCSTR name, SEGPTR sbuf, INT16 buflen) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_AsyncGetProtoByName(%08x): hwnd %04x, msg %04x, protocol %s\n", (unsigned)pwsi, hWnd, uMsg, (name)?name:NULL_STRING ); if( pwsi ) return __WSAsyncDBQuery(pwsi, hWnd, uMsg, 0, name, 0, NULL, sbuf, buflen, WSMSG_ASYNC_PROTOBYNAME ); return 0; } /*********************************************************************** * WSAAsyncGetProtoByNumber() (WINSOCK.104) */ HANDLE16 WINAPI WSAAsyncGetProtoByNumber(HWND16 hWnd, UINT16 uMsg, INT16 number, SEGPTR sbuf, INT16 buflen) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_AsyncGetProtoByNumber(%08x): hwnd %04x, msg %04x, num %i\n", (unsigned)pwsi, hWnd, uMsg, number ); if( pwsi ) return __WSAsyncDBQuery(pwsi, hWnd, uMsg, number, NULL, 0, NULL, sbuf, buflen, WSMSG_ASYNC_PROTOBYNUM ); return 0; } /*********************************************************************** * WSAAsyncGetServByName() (WINSOCK.107) */ HANDLE16 WINAPI WSAAsyncGetServByName(HWND16 hWnd, UINT16 uMsg, LPCSTR name, LPCSTR proto, SEGPTR sbuf, INT16 buflen) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_AsyncGetServByName(%08x): hwnd %04x, msg %04x, name %s, proto %s\n", (unsigned)pwsi, hWnd, uMsg, (name)?name:NULL_STRING, (proto)?proto:NULL_STRING ); if( pwsi ) return __WSAsyncDBQuery(pwsi, hWnd, uMsg, 0, name, 0, proto, sbuf, buflen, WSMSG_ASYNC_SERVBYNAME ); return 0; } /*********************************************************************** * WSAAsyncGetServByPort() (WINSOCK.106) */ HANDLE16 WINAPI WSAAsyncGetServByPort(HWND16 hWnd, UINT16 uMsg, INT16 port, LPCSTR proto, SEGPTR sbuf, INT16 buflen) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_AsyncGetServByPort(%08x): hwnd %04x, msg %04x, port %i, proto %s\n", (unsigned)pwsi, hWnd, uMsg, port, (proto)?proto:NULL_STRING ); if( pwsi ) return __WSAsyncDBQuery(pwsi, hWnd, uMsg, port, proto, 0, NULL, sbuf, buflen, WSMSG_ASYNC_SERVBYPORT ); return 0; } /*********************************************************************** * WSACancelAsyncRequest() (WINSOCK.108) */ INT16 WINAPI WSACancelAsyncRequest(HANDLE16 hAsyncTaskHandle) { INT16 retVal = SOCKET_ERROR; LPWSINFO pwsi = wsi_find(GetCurrentTask()); ws_async_op* p_aop = (ws_async_op*)WS_HANDLE2PTR(hAsyncTaskHandle); dprintf_winsock(stddeb, "WS_CancelAsyncRequest(%08x): handle %04x\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; } /*********************************************************************** * WSAAsyncSelect() (WINSOCK.101) */ static ws_select_op* __ws_select_list = NULL; BOOL32 WINSOCK_HandleIO( int* max_fd, int num_pending, fd_set io_set[3] ) { /* This function is called by the event dispatcher * with io_set containing the result of select() */ ws_select_op* psop = __ws_select_list; BOOL32 bPost = FALSE; DWORD dwEvent, dwErrBytes; int num_posted; dprintf_winsock(stddeb,"WINSOCK_HandleIO: %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, &io_set[EVENT_IO_READ] )) || (w = FD_ISSET( fd, &io_set[EVENT_IO_WRITE] )) || (e = FD_ISSET( fd, &io_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. */ dprintf_winsock(stddeb,"\tchecking psop = 0x%08x\n", (unsigned) psop ); num_pending--; if( flags & WS_FD_ACCEPT ) { /* listening socket */ FD_CLR( fd, &io_set[EVENT_IO_WRITE] ); if( r ) { FD_CLR( fd, &io_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, &io_set[EVENT_IO_WRITE] )) ) { /* ready to write means that socket is connected */ 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, &io_set[EVENT_IO_READ] ); if( flags & WS_FD_WRITE ) FD_SET( fd, &io_set[EVENT_IO_WRITE] ); else FD_CLR( fd, &io_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 */ } else { /* connected socket -- * removed WS_FD_OOB code for now. */ if( flags & WS_FD_WRITE && (w || (w = FD_ISSET( fd, &io_set[EVENT_IO_WRITE] ))) ) { /* this will be reenabled when send() or sendto() fail with * WSAEWOULDBLOCK */ if( PostMessage16( psop->hWnd, psop->uMsg, (WPARAM16)WS_PTR2HANDLE(psop->pws), (LPARAM)WSAMAKESELECTREPLY( WS_FD_WRITE, 0 ) ) ) { FD_CLR( fd, &io_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, &io_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, &io_set[EVENT_IO_READ] ); FD_CLR( fd, &io_set[EVENT_IO_WRITE] ); if( *max_fd == (fd + 1) ) (*max_fd)--; } } } if( bPost ) { PostMessage16( psop->hWnd, psop->uMsg, (WPARAM16)WS_PTR2HANDLE(psop->pws), (LPARAM)dwEvent ); bPost = FALSE; num_posted++; } } if( num_pending <= 0 ) break; } dprintf_winsock(stddeb, "\tdone, %i posted events\n", num_posted ); return ( num_posted ) ? TRUE : FALSE; } INT16 WINAPI WSAAsyncSelect(SOCKET16 s, HWND16 hWnd, UINT16 uMsg, UINT32 lEvent) { ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_AsyncSelect(%08x): %04x, hWnd %04x, uMsg %04x, event %08x\n", (unsigned)pwsi, s, 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 ); dprintf_winsock(stddeb,"\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 */ dprintf_winsock(stddeb,"\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; } /*********************************************************************** * __WSAFDIsSet() (WINSOCK.151) */ INT16 WINAPI __WSAFDIsSet16(SOCKET16 s, ws_fd_set *set) { int i = set->fd_count; dprintf_winsock(stddeb, "__WSAFDIsSet(%d,%8lx)\n", s,(unsigned long)set); while (i--) if (set->fd_array[i] == s) return 1; return 0; } /*********************************************************************** * __WSAFDIsSet() (WSOCK32.151) */ INT32 WINAPI __WSAFDIsSet32(SOCKET32 s, ws_fd_set *set) { return __WSAFDIsSet16( (SOCKET16)s, set ); } /*********************************************************************** * WSAIsBlocking() (WINSOCK.114)(WSOCK32.114) */ BOOL32 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 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(). */ dprintf_winsock(stddeb, "WS_IsBlocking()\n"); return FALSE; } /*********************************************************************** * WSACancelBlockingCall() (WINSOCK.113)(WSOCK32.113) */ INT32 WINAPI WSACancelBlockingCall(void) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_CancelBlockingCall(%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()); dprintf_winsock(stddeb, "WS_SetBlockingHook16(%08x): hook %08x\n", (unsigned)pwsi, (unsigned) lpBlockFunc); if( pwsi ) { prev = (FARPROC16)pwsi->blocking_hook; pwsi->blocking_hook = (DWORD)lpBlockFunc; pwsi->flags &= ~WSI_BLOCKINGHOOK32; return prev; } return 0; } /*********************************************************************** * WSASetBlockingHook32() */ FARPROC32 WINAPI WSASetBlockingHook32(FARPROC32 lpBlockFunc) { FARPROC32 prev; LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_SetBlockingHook32(%08x): hook %08x\n", (unsigned)pwsi, (unsigned) lpBlockFunc); if( pwsi ) { prev = (FARPROC32)pwsi->blocking_hook; pwsi->blocking_hook = (DWORD)lpBlockFunc; pwsi->flags |= WSI_BLOCKINGHOOK32; return prev; } return NULL; } /*********************************************************************** * WSAUnhookBlockingHook16() (WINSOCK.110) */ INT16 WINAPI WSAUnhookBlockingHook16(void) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_UnhookBlockingHook16(%08x)\n", (unsigned)pwsi); if( pwsi ) return (INT16)(pwsi->blocking_hook = 0); return SOCKET_ERROR; } /*********************************************************************** * WSAUnhookBlockingHook32() */ INT32 WINAPI WSAUnhookBlockingHook32(void) { LPWSINFO pwsi = wsi_find(GetCurrentTask()); dprintf_winsock(stddeb, "WS_UnhookBlockingHook32(%08x)\n", (unsigned)pwsi); if( pwsi ) { pwsi->blocking_hook = 0; pwsi->flags &= ~WSI_BLOCKINGHOOK32; return 0; } return SOCKET_ERROR; } /*********************************************************************** * WsControl() */ VOID WINAPI WsControl(DWORD x1,DWORD x2,LPDWORD x3,LPDWORD x4, LPDWORD x5,LPDWORD x6) { fprintf(stdnimp,"WsControl(%lx,%lx,%p,%p,%p,%p)\n", x1,x2,x3,x4,x5,x6 ); fprintf(stdnimp,"WsControl(x,x,%lx,%lx,%lx,%lx)\n", x3?*x3:0,x4?*x4:0,x5?*x5:0,x6?*x6:0 ); return; } /* ----------------------------------- end of API stuff */ /* ----------------------------------- helper functions */ 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;ih_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) { /* Duplicate hostent structure and flatten data (with its pointers) * 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 ) { char* p_name,*p_aliases,*p_addr,*p_base,*p; _check_buffer(pwsi, size); p = pwsi->buffer; p_base = (flag & WS_DUP_OFFSET) ? NULL : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p); p += (flag & WS_DUP_NATIVE) ? sizeof(struct hostent) : 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 - pwsi->buffer), 0); p_addr = p; list_dup(p_he->h_addr_list, p, p_base + (p - pwsi->buffer), p_he->h_length); if( flag & WS_DUP_NATIVE ) { struct hostent* p_to = (struct hostent*)pwsi->buffer; p_to->h_addrtype = p_he->h_addrtype; p_to->h_length = p_he->h_length; p_to->h_name = p_base + (p_name - pwsi->buffer); p_to->h_aliases = (char**)(p_base + (p_aliases - pwsi->buffer)); p_to->h_addr_list = (char**)(p_base + (p_addr - pwsi->buffer)); } else { struct ws_hostent* p_to = (struct ws_hostent*)pwsi->buffer; 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 - pwsi->buffer)); p_to->h_aliases = (SEGPTR)(p_base + (p_aliases - pwsi->buffer)); p_to->h_addr_list = (SEGPTR)(p_base + (p_addr - pwsi->buffer)); return (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 ) { char* p_name,*p_aliases,*p_base,*p; _check_buffer(pwsi, size); p = pwsi->buffer; p_base = (flag & WS_DUP_OFFSET) ? NULL : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p); p += (flag & WS_DUP_NATIVE)? sizeof(struct protoent) : 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 - pwsi->buffer), 0); if( flag & WS_DUP_NATIVE ) { struct protoent* p_to = (struct protoent*)pwsi->buffer; p_to->p_proto = p_pe->p_proto; p_to->p_name = p_base + (p_name - pwsi->buffer); p_to->p_aliases = (char**)(p_base + (p_aliases - pwsi->buffer)); } else { struct ws_protoent* p_to = (struct ws_protoent*)pwsi->buffer; p_to->p_proto = (INT16)p_pe->p_proto; p_to->p_name = (SEGPTR)(p_base) + (p_name - pwsi->buffer); p_to->p_aliases = (SEGPTR)((p_base) + (p_aliases - pwsi->buffer)); return (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 ) { char* p_name,*p_aliases,*p_proto,*p_base,*p; _check_buffer(pwsi, size); p = pwsi->buffer; p_base = (flag & WS_DUP_OFFSET) ? NULL : ((flag & WS_DUP_SEGPTR) ? (char*)SEGPTR_GET(p) : p); p += (flag & WS_DUP_NATIVE)? sizeof(struct servent) : 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 - pwsi->buffer), 0); if( flag & WS_DUP_NATIVE ) { struct servent* p_to = (struct servent*)pwsi->buffer; p_to->s_port = p_se->s_port; p_to->s_name = p_base + (p_name - pwsi->buffer); p_to->s_proto = p_base + (p_proto - pwsi->buffer); p_to->s_aliases = (char**)(p_base + (p_aliases - pwsi->buffer)); } else { struct ws_servent* p_to = (struct ws_servent*)pwsi->buffer; p_to->s_port = (INT16)p_se->s_port; p_to->s_name = (SEGPTR)(p_base + (p_name - pwsi->buffer)); p_to->s_proto = (SEGPTR)(p_base + (p_proto - pwsi->buffer)); p_to->s_aliases = (SEGPTR)(p_base + (p_aliases - pwsi->buffer)); return (size + sizeof(struct ws_servent) - sizeof(struct servent)); } } return size; } /* ----------------------------------- error handling */ UINT16 wsaErrno(void) { int loc_errno = errno; #if defined(__FreeBSD__) dprintf_winsock(stderr, "winsock: errno %d, (%s).\n", errno, sys_errlist[errno]); #else dprintf_winsock(stderr, "winsock: errno %d\n", 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 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: fprintf(stderr, "winsock: unknown errno %d!\n", errno); return WSAEOPNOTSUPP; } } UINT16 wsaHerrno(void) { int loc_errno = h_errno; #if defined(__FreeBSD__) dprintf_winsock(stderr, "winsock: h_errno %d, (%s).\n", h_errno, sys_errlist[h_errno]); #else dprintf_winsock(stderr, "winsock: h_errno %d.\n", h_errno); #ifndef sun if( debugging_winsock ) herror("wine: winsock: wsaherrno"); #endif #endif 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: fprintf(stderr, "winsock: unknown h_errno %d!\n", h_errno); return WSAEOPNOTSUPP; } }