| /* |
| * based on Windows Sockets 1.1 specs |
| * (ftp.microsoft.com:/Advsys/winsock/spec11/WINSOCK.TXT) |
| * |
| * (C) 1993,1994,1996 John Brezak, Erik Bos, Alex Korobka. |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <signal.h> |
| #include <sys/types.h> |
| #include <sys/ipc.h> |
| #include <sys/ioctl.h> |
| #if defined(__svr4__) |
| #include <sys/filio.h> |
| #include <sys/ioccom.h> |
| #include <sys/sockio.h> |
| #endif |
| #if defined(__EMX__) |
| #include <sys/so_ioctl.h> |
| #include <sys/param.h> |
| #endif |
| #include <sys/msg.h> |
| #include <sys/wait.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| #include <arpa/inet.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <netdb.h> |
| #include <unistd.h> |
| |
| #include "windows.h" |
| #include "winnt.h" |
| #include "heap.h" |
| #include "ldt.h" |
| #include "winsock.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)) |
| |
| extern void SIGNAL_MaskAsyncEvents( BOOL32 ); |
| |
| #pragma pack(4) |
| |
| /* ----------------------------------- internal data */ |
| |
| extern int h_errno; |
| extern void __sigio(int); |
| |
| ws_async_ctl async_ctl; |
| int async_qid = -1; |
| |
| 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 INT16 _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 INT16 init_async_select(ws_socket* pws, HWND16 hWnd, UINT16 uMsg, UINT32 lEvent); |
| static int notify_client(ws_socket* pws, unsigned flag); |
| |
| static int _check_ws(LPWSINFO pwsi, ws_socket* pws); |
| static int _check_buffer(LPWSINFO pwsi, int size); |
| |
| static void fixup_wshe(struct ws_hostent* p_wshe, SEGPTR base); |
| static void fixup_wspe(struct ws_protoent* p_wspe, SEGPTR base); |
| static void fixup_wsse(struct ws_servent* p_wsse, SEGPTR base); |
| |
| static int cancel_async_select(ws_socket*); |
| |
| static void convert_sockopt(INT16 *level, INT16 *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 = (INT16)_px_sock_ops[i]; |
| else fprintf(stderr, "convert_sockopt() unknown optname %d\n", *optname); |
| break; |
| case WS_IPPROTO_TCP: |
| *optname = IPPROTO_TCP; |
| } |
| } |
| |
| static void _ws_global_init() |
| { |
| 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"); |
| } |
| if( async_qid == -1 ) |
| if( (async_qid = msgget(IPC_PRIVATE, IPC_CREAT | 0x1FF)) == -1 ) |
| fprintf(stderr,"Fatal: failed to create WinSock resource\n"); |
| } |
| |
| /* ----------------------------------- Per-thread info */ |
| |
| static void wsi_link(LPWSINFO pwsi) |
| { if( _wsi_list ) _wsi_list->prev = pwsi; |
| pwsi->next = _wsi_list; _wsi_list = pwsi; |
| } |
| |
| static void wsi_unlink(LPWSINFO pwsi) |
| { |
| if( pwsi == _wsi_list ) _wsi_list = pwsi->next; |
| else |
| { pwsi->prev->next = pwsi->next; |
| if( pwsi->next ) pwsi->next->prev = pwsi->prev; } |
| } |
| |
| static LPWSINFO wsi_find(HTASK16 hTask) |
| { LPWSINFO pwsi = _wsi_list; |
| while( pwsi && pwsi->tid != hTask ) pwsi = pwsi->next; |
| return pwsi; |
| } |
| |
| static ws_socket* wsi_alloc_socket(LPWSINFO pwsi, int fd) |
| { |
| if( pwsi->last_free >= 0 ) |
| { |
| int i = pwsi->last_free; |
| |
| pwsi->last_free = pwsi->sock[i].flags; |
| 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) |
| { |
| 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; |
| } |
| |
| static void fd_set_update_except(LPWSINFO pwsi, fd_set *fds, ws_fd_set *ws, |
| fd_set *errorfds) |
| { |
| if (ws) |
| { |
| int i, j, count = ws->fd_count; |
| |
| for (i=j=0; i < count; i++) |
| { |
| ws_socket *pws = (ws_socket *)WS_HANDLE2PTR(ws->fd_array[i]); |
| |
| if (_check_ws(pwsi, pws) && (FD_ISSET(pws->fd, fds) |
| || FD_ISSET(pws->fd, errorfds))) |
| ws->fd_array[j++] = ws->fd_array[i]; |
| } |
| ws->fd_count = j; |
| } |
| return; |
| } |
| |
| /* ----------------------------------- API ----- |
| * |
| * Init / cleanup / error checking. |
| */ |
| |
| INT16 WSAStartup(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", |
| #else |
| "Unknown", |
| #endif |
| WS_MAX_SOCKETS_PER_THREAD, |
| WS_MAX_UDP_DATAGRAM, 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; |
| |
| _ws_global_init(); |
| if( _WSHeap == 0 ) return WSASYSNOTREADY; |
| |
| pwsi = wsi_find(GetCurrentTask()); |
| if( pwsi == NULL ) |
| { |
| 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; |
| wsi_link(pwsi); |
| } else pwsi->num_startup++; |
| |
| /* return winsock information */ |
| memcpy(lpWSAData, &WINSOCK_data, sizeof(WINSOCK_data)); |
| |
| dprintf_winsock(stddeb, "WSAStartup: succeeded\n"); |
| return(0); |
| } |
| |
| void WINSOCK_Shutdown() |
| { |
| if( async_qid != -1 ) |
| if( msgctl(async_qid, IPC_RMID, NULL) == -1 ) |
| fprintf(stderr,"failed to delete WS message queue.\n"); |
| else async_qid = -1; |
| } |
| |
| INT16 WSACleanup(void) |
| { |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| /* FIXME: do global cleanup if no current task */ |
| |
| dprintf_winsock(stddeb, "WSACleanup(%08x)\n", (unsigned)pwsi); |
| if( pwsi ) |
| { |
| int i, j, n; |
| |
| if( pwsi->num_startup-- ) return 0; |
| |
| SIGNAL_MaskAsyncEvents( TRUE ); |
| WINSOCK_cancel_async_op(GetCurrentTask()); |
| SIGNAL_MaskAsyncEvents( FALSE ); |
| |
| wsi_unlink(pwsi); |
| if( _wsi_list == NULL ) WINSOCK_Shutdown(); |
| |
| if( pwsi->flags & WSI_BLOCKINGCALL ) |
| dprintf_winsock(stddeb,"\tinside blocking call!\n"); |
| 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 ) |
| { |
| n += cancel_async_select(&pwsi->sock[i]); |
| close(pwsi->sock[i].fd); j++; |
| } |
| if( j ) |
| dprintf_winsock(stddeb,"\tclosed %i sockets, killed %i async selects!\n", j, n); |
| |
| if( pwsi->buffer ) SEGPTR_FREE(pwsi->buffer); |
| if( pwsi->dbuffer ) SEGPTR_FREE(pwsi->dbuffer); |
| WS_FREE(pwsi); |
| return 0; |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 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; |
| } |
| |
| void WSASetLastError(INT16 iError) |
| { |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WSASetLastError(%08x): %d\n", (unsigned)pwsi, (int)iError); |
| |
| if( pwsi ) pwsi->err = 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); |
| } |
| |
| /* ----- socket operations */ |
| |
| SOCKET16 WINSOCK_accept(SOCKET16 s, struct sockaddr *addr, INT16 *addrlen16) |
| { |
| ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(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, addrlen32 = *addrlen16; |
| |
| /* this is how block info is supposed to be used - |
| * WSAIsBlocking() would then check WSI_BLOCKINGCALL bit. |
| */ |
| |
| fd_flags = fcntl(pws->fd, F_GETFL, 0); |
| if( !(fd_flags & O_NONBLOCK) ) pwsi->flags |= WSI_BLOCKINGCALL; |
| |
| if( (sock = accept(pws->fd, addr, &addrlen32)) >= 0 ) |
| { |
| ws_socket* pnew = wsi_alloc_socket(pwsi, sock); |
| notify_client(pws, WS_FD_ACCEPT); |
| if( pnew ) |
| { |
| if( pws->p_aop ) |
| init_async_select(pnew, pws->p_aop->hWnd, |
| pws->p_aop->uMsg, |
| pws->p_aop->flags & ~WS_FD_ACCEPT ); |
| |
| pwsi->flags &= ~WSI_BLOCKINGCALL; |
| return (SOCKET16)WS_PTR2HANDLE(pnew); |
| } |
| else pwsi->err = WSAENOBUFS; |
| } |
| else pwsi->err = wsaErrno(); |
| |
| pwsi->flags &= ~WSI_BLOCKINGCALL; |
| } |
| return INVALID_SOCKET; |
| } |
| |
| INT16 WINSOCK_bind(SOCKET16 s, struct sockaddr *name, INT16 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; |
| else pwsi->err = WSAEAFNOSUPPORT; |
| else pwsi->err = WSAEFAULT; |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_closesocket(SOCKET16 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; |
| |
| cancel_async_select(pws); |
| pws->fd = -1; |
| pws->flags = (unsigned)pwsi->last_free; |
| pwsi->last_free = pws - &pwsi->sock[0]; |
| if (close(fd) == 0) return 0; |
| pwsi->err = (errno == EBADF) ? WSAENOTSOCK : wsaErrno(); |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_connect(SOCKET16 s, struct sockaddr *name, INT16 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) |
| { |
| if( pws->p_aop ) |
| /* we need to notify handler process if |
| * connect() succeeded NOT in response to winsock message |
| */ |
| notify_client(pws, WS_FD_CONNECTED); |
| |
| pws->flags &= ~(WS_FD_INACTIVE | WS_FD_CONNECT); |
| return 0; |
| } |
| pwsi->err = (errno == EINPROGRESS) ? WSAEWOULDBLOCK : wsaErrno(); |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_getpeername(SOCKET16 s, struct sockaddr *name, INT16 *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) ) |
| { |
| int namelen32 = *namelen; |
| if (getpeername(pws->fd, name, &namelen32) == 0) |
| { |
| #if 0 |
| dump_sockaddr(name); |
| #endif |
| *namelen = (INT16)namelen32; |
| return 0; |
| } |
| pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_getsockname(SOCKET16 s, struct sockaddr *name, INT16 *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) ) |
| { |
| int namelen32 = *namelen; |
| if (getsockname(pws->fd, name, &namelen32) == 0) |
| { |
| *namelen = (INT16)namelen32; |
| return 0; |
| } |
| pwsi->err = (h_errno < 0) ? wsaErrno() : wsaHerrno(); |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_getsockopt(SOCKET16 s, INT16 level, |
| INT16 optname, char *optval, INT16 *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) ) |
| { |
| int optlen32 = *optlen; |
| |
| convert_sockopt(&level, &optname); |
| if (getsockopt(pws->fd, (int) level, optname, optval, &optlen32) == 0 ) |
| { *optlen = (INT16)optlen32; return 0; } |
| pwsi->err = (errno == EBADF) ? WSAENOTSOCK : wsaErrno(); |
| } |
| return SOCKET_ERROR; |
| } |
| |
| u_long WINSOCK_htonl(u_long hostlong) { return( htonl(hostlong) ); } |
| u_short WINSOCK_htons(u_short hostshort) { return( htons(hostshort) ); } |
| u_long WINSOCK_inet_addr(char *cp) { return( inet_addr(cp) ); } |
| u_long WINSOCK_ntohl(u_long netlong) { return( ntohl(netlong) ); } |
| u_short WINSOCK_ntohs(u_short netshort) { return( ntohs(netshort) ); } |
| |
| SEGPTR 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; |
| } |
| |
| INT16 WINSOCK_ioctlsocket(SOCKET16 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->p_aop && *argp == 0 ) |
| { |
| 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: fprintf(stderr,"Warning: Unknown 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; |
| } |
| |
| INT16 WINSOCK_listen(SOCKET16 s, INT16 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->p_aop ) |
| { |
| int fd_flags = fcntl(pws->fd, F_GETFL, 0); |
| if( !(fd_flags & O_NONBLOCK) ) pws->flags |= WS_FD_ACCEPT; |
| } |
| else notify_client(pws, WS_FD_ACCEPT); |
| |
| if (listen(pws->fd, backlog) == 0) return 0; |
| pwsi->err = wsaErrno(); |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_recv(SOCKET16 s, char *buf, INT16 len, INT16 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) ) |
| { |
| int length; |
| if ((length = recv(pws->fd, buf, len, flags)) >= 0) |
| { |
| dprintf_winsock(stddeb, " -> %i bytes\n", length); |
| notify_client(pws, WS_FD_READ); |
| return (INT16)length; |
| } |
| pwsi->err = wsaErrno(); |
| } |
| dprintf_winsock(stddeb, " -> ERROR\n"); |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_recvfrom(SOCKET16 s, char *buf, INT16 len, INT16 flags, |
| struct sockaddr *from, INT16 *fromlen16) |
| { |
| 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\n", |
| (unsigned)pwsi, s, (unsigned)buf, len, flags); |
| if( _check_ws(pwsi, pws) ) |
| { |
| int length, fromlen32 = *fromlen16; |
| |
| if ((length = recvfrom(pws->fd, buf, len, flags, from, &fromlen32)) >= 0) |
| { |
| *fromlen16 = fromlen32; |
| notify_client(pws, WS_FD_READ); |
| return (INT16)length; |
| } |
| pwsi->err = wsaErrno(); |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_select(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); |
| fd_set_update_except(pwsi, &exceptfds, ws_exceptfds, &errorfds); |
| } |
| return highfd; |
| } |
| pwsi->err = wsaErrno(); |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_send(SOCKET16 s, char *buf, INT16 len, INT16 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 ) |
| { |
| length = SOCKET_ERROR; |
| pwsi->err = wsaErrno(); |
| } |
| notify_client(pws, WS_FD_WRITE); |
| return (INT16)length; |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_sendto(SOCKET16 s, char *buf, INT16 len, INT16 flags, |
| struct sockaddr *to, INT16 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) ) |
| { |
| int length; |
| |
| if ((length = sendto(pws->fd, buf, len, flags, to, tolen)) < 0 ) |
| { |
| length = SOCKET_ERROR; |
| pwsi->err = wsaErrno(); |
| } |
| notify_client(pws, WS_FD_WRITE); |
| return (INT16)length; |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_setsockopt(SOCKET16 s, INT16 level, INT16 optname, |
| char *optval, INT16 optlen) |
| { |
| ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(s); |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WS_SETSOCKOPT(%08x): socket %04x, level %d, opt %d, ptr %08x, len %d\n", |
| (unsigned)pwsi, s, level, optname, (int) optval, optlen); |
| if( _check_ws(pwsi, pws) ) |
| { |
| int linger32[2]; |
| convert_sockopt(&level, &optname); |
| if( optname == SO_LINGER ) |
| { |
| INT16* ptr = (INT16*)optval; |
| linger32[0] = ptr[0]; |
| linger32[1] = ptr[1]; |
| optval = (char*)&linger32; |
| optlen = sizeof(linger32); |
| } |
| if (setsockopt(pws->fd, level, optname, optval, optlen) == 0) return 0; |
| pwsi->err = wsaErrno(); |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 WINSOCK_shutdown(SOCKET16 s, INT16 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) ) |
| { |
| pws->flags |= WS_FD_INACTIVE; |
| cancel_async_select(pws); |
| |
| if (shutdown(pws->fd, how) == 0) return 0; |
| pwsi->err = wsaErrno(); |
| } |
| return SOCKET_ERROR; |
| } |
| |
| SOCKET16 WINSOCK_socket(INT16 af, INT16 type, INT16 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_SOCKET; |
| } |
| |
| /* check the socket type */ |
| switch(type) |
| { |
| case SOCK_STREAM: |
| case SOCK_DGRAM: |
| case SOCK_RAW: break; |
| default: pwsi->err = WSAESOCKTNOSUPPORT; return INVALID_SOCKET; |
| } |
| |
| /* check the protocol type */ |
| if ( protocol < 0 ) /* don't support negative values */ |
| { pwsi->err = WSAEPROTONOSUPPORT; return INVALID_SOCKET; } |
| |
| 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_SOCKET; |
| } |
| |
| 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_SOCKET; |
| } |
| } |
| |
| 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_SOCKET; |
| } |
| |
| |
| /* ----- database functions |
| * |
| * Note that ws_...ent structures we return have SEGPTR pointers inside them. |
| */ |
| |
| static char* NULL_STRING = "NULL"; |
| |
| /* |
| struct WIN_hostent * |
| */ |
| SEGPTR WINSOCK_gethostbyaddr(const char *addr, INT16 len, INT16 type) |
| { |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WS_GetHostByAddr(%08x): ptr %8x, len %d, type %d\n", |
| (unsigned)pwsi, (unsigned) addr, len, type); |
| if( pwsi ) |
| { |
| struct hostent* host; |
| if( (host = gethostbyaddr(addr, len, type)) != 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 NULL; |
| } |
| |
| /* |
| struct WIN_hostent * |
| */ |
| SEGPTR WINSOCK_gethostbyname(const char *name) |
| { |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WS_GetHostByName(%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 NULL; |
| } |
| |
| INT16 WINSOCK_gethostname(char *name, INT16 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; |
| } |
| |
| /* |
| struct WIN_protoent * |
| */ |
| SEGPTR WINSOCK_getprotobyname(char *name) |
| { |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WS_GetProtoByName(%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 NULL; |
| } |
| |
| /* |
| struct WIN_protoent * |
| */ |
| SEGPTR WINSOCK_getprotobynumber(INT16 number) |
| { |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WS_GetProtoByNumber(%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 NULL; |
| } |
| |
| /* |
| struct WIN_servent * |
| */ |
| SEGPTR WINSOCK_getservbyname(const char *name, const char *proto) |
| { |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WS_GetServByName(%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 NULL; |
| } |
| |
| /* |
| struct WIN_servent * |
| */ |
| SEGPTR WINSOCK_getservbyport(INT16 port, const char *proto) |
| { |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WS_GetServByPort(%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 NULL; |
| } |
| |
| |
| /* ----------------------------------- Windows sockets extensions -- * |
| * * |
| * ----------------------------------------------------------------- */ |
| |
| static int aop_control(ws_async_op* p_aop, int flag ) |
| { |
| unsigned lLength; |
| |
| read(p_aop->fd[0], &lLength, sizeof(unsigned)); |
| if( LOWORD(lLength) ) |
| if( (int)LOWORD(lLength) <= p_aop->buflen ) |
| { |
| char* buffer = (char*)PTR_SEG_TO_LIN(p_aop->buffer_base); |
| read(p_aop->fd[0], buffer, LOWORD(lLength)); |
| switch( p_aop->flags ) |
| { |
| case WSMSG_ASYNC_HOSTBYNAME: |
| case WSMSG_ASYNC_HOSTBYADDR: |
| fixup_wshe((struct ws_hostent*)buffer, p_aop->buffer_base); break; |
| case WSMSG_ASYNC_PROTOBYNAME: |
| case WSMSG_ASYNC_PROTOBYNUM: |
| fixup_wspe((struct ws_protoent*)buffer, p_aop->buffer_base); break; |
| case WSMSG_ASYNC_SERVBYNAME: |
| case WSMSG_ASYNC_SERVBYPORT: |
| fixup_wsse((struct ws_servent*)buffer, p_aop->buffer_base); break; |
| default: |
| if( p_aop->flags ) fprintf(stderr,"Received unknown async request!\n"); |
| return AOP_CONTROL_REMOVE; |
| } |
| } |
| else lLength = ((UINT32)LOWORD(lLength)) | ((unsigned)WSAENOBUFS << 16); |
| |
| #if 0 |
| printf("async op completed: hWnd [%04x], uMsg [%04x], aop [%04x], event [%08x]\n", |
| p_aop->hWnd, p_aop->uMsg, (HANDLE16)WS_PTR2HANDLE(p_aop), (LPARAM)lLength); |
| #endif |
| |
| PostMessage16(p_aop->hWnd, p_aop->uMsg, (HANDLE16)WS_PTR2HANDLE(p_aop), (LPARAM)lLength); |
| return AOP_CONTROL_REMOVE; |
| } |
| |
| |
| static HANDLE16 __WSAsyncDBQuery(LPWSINFO pwsi, HWND16 hWnd, UINT16 uMsg, LPCSTR init, |
| INT16 len, INT16 type, SEGPTR sbuf, INT16 buflen, UINT32 flag) |
| { |
| /* queue 'flag' request and fork off its handler */ |
| |
| async_ctl.ws_aop = (ws_async_op*)WS_ALLOC(sizeof(ws_async_op)); |
| |
| if( async_ctl.ws_aop ) |
| { |
| HANDLE16 handle = (HANDLE16)WS_PTR2HANDLE(async_ctl.ws_aop); |
| |
| if( pipe(async_ctl.ws_aop->fd) == 0 ) |
| { |
| async_ctl.init = (char*)init; |
| async_ctl.lLength = len; |
| async_ctl.lEvent = type; |
| |
| async_ctl.ws_aop->hWnd = hWnd; |
| async_ctl.ws_aop->uMsg = uMsg; |
| |
| async_ctl.ws_aop->buffer_base = sbuf; async_ctl.ws_aop->buflen = buflen; |
| async_ctl.ws_aop->flags = flag; |
| async_ctl.ws_aop->aop_control = &aop_control; |
| WINSOCK_link_async_op( async_ctl.ws_aop ); |
| |
| async_ctl.ws_aop->pid = fork(); |
| if( async_ctl.ws_aop->pid ) |
| { |
| close(async_ctl.ws_aop->fd[1]); /* write endpoint */ |
| |
| /* Damn, BSD'ish SIGIO doesn't work on pipes/streams |
| * |
| * async_io(async_ctl.ws_aop->fd[0], 1); |
| */ |
| |
| dprintf_winsock(stddeb, "\tasync_op = %04x (child %i)\n", |
| handle, async_ctl.ws_aop->pid); |
| return handle; |
| } else |
| /* child process */ |
| { |
| close(async_ctl.ws_aop->fd[0]); /* read endpoint */ |
| switch(flag) |
| { |
| case WSMSG_ASYNC_HOSTBYADDR: |
| case WSMSG_ASYNC_HOSTBYNAME: |
| WS_do_async_gethost(pwsi,flag); |
| case WSMSG_ASYNC_PROTOBYNUM: |
| case WSMSG_ASYNC_PROTOBYNAME: |
| WS_do_async_getproto(pwsi,flag); |
| case WSMSG_ASYNC_SERVBYPORT: |
| case WSMSG_ASYNC_SERVBYNAME: |
| WS_do_async_getserv(pwsi,flag); |
| } |
| _exit(0); /* skip atexit()'ed cleanup */ |
| } |
| } |
| WS_FREE(async_ctl.ws_aop); |
| pwsi->err = wsaErrno(); |
| } else pwsi->err = WSAEWOULDBLOCK; |
| return 0; |
| } |
| |
| HANDLE16 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, addr, len, |
| type, sbuf, buflen, WSMSG_ASYNC_HOSTBYADDR ); |
| return 0; |
| } |
| |
| |
| HANDLE16 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, name, 0, |
| 0, sbuf, buflen, WSMSG_ASYNC_HOSTBYNAME ); |
| return 0; |
| } |
| |
| |
| HANDLE16 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, name, 0, |
| 0, sbuf, buflen, WSMSG_ASYNC_PROTOBYNAME ); |
| return 0; |
| } |
| |
| |
| HANDLE16 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, NULL, 0, |
| number, sbuf, buflen, WSMSG_ASYNC_PROTOBYNUM ); |
| return 0; |
| } |
| |
| |
| HANDLE16 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 ) |
| { |
| async_ctl.buffer = (char*)proto; |
| return __WSAsyncDBQuery(pwsi, hWnd, uMsg, name, 0, |
| 0, sbuf, buflen, WSMSG_ASYNC_SERVBYNAME ); |
| } |
| return 0; |
| } |
| |
| |
| HANDLE16 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, proto, 0, |
| port, sbuf, buflen, WSMSG_ASYNC_SERVBYPORT ); |
| return 0; |
| } |
| |
| INT16 WSACancelAsyncRequest(HANDLE16 hAsyncTaskHandle) |
| { |
| 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 ) |
| if( WINSOCK_check_async_op(p_aop) ) |
| { |
| kill(p_aop->pid, SIGKILL); |
| waitpid(p_aop->pid, NULL, 0); /* just in case */ |
| close(p_aop->fd[0]); |
| WINSOCK_unlink_async_op(p_aop); |
| WS_FREE(p_aop); |
| return 0; |
| } |
| else pwsi->err = WSAEINVAL; |
| return SOCKET_ERROR; |
| } |
| |
| /* ----- asynchronous select() */ |
| |
| int cancel_async_select(ws_socket* pws) |
| { |
| if( pws->p_aop ) |
| { |
| kill(pws->p_aop->pid, SIGKILL); |
| waitpid(pws->p_aop->pid, NULL, 0); |
| WS_FREE(pws->p_aop); |
| pws->p_aop = NULL; |
| return 1; |
| } |
| return 0; |
| } |
| |
| void _sigusr1_handler_parent(int sig) |
| { |
| /* child process puts MTYPE_CLIENT data packet into the |
| * 'async_qid' message queue and signals us with SIGUSR1. |
| * This handler reads the queue and posts 'uMsg' notification |
| * message. |
| */ |
| |
| ipc_packet ipack; |
| |
| signal( SIGUSR1, _sigusr1_handler_parent); |
| while( msgrcv(async_qid, (struct msgbuf*)&ipack, |
| MTYPE_CLIENT_SIZE, MTYPE_CLIENT, IPC_NOWAIT) != -1 ) |
| { |
| if( ipack.wParam && abs((short)ipack.wParam) < 32768 ) |
| { |
| ws_socket* pws = (ws_socket*)WS_HANDLE2PTR(ipack.wParam); |
| if( pws->p_aop && abs((char*)_ws_stub - (char*)pws->p_aop) < 32768 ) |
| { |
| pws->flags &= ~(ipack.lParam); |
| #if 0 |
| printf("async event - hWnd %04x, uMsg %04x [%08x]\n", |
| pws->p_aop->hWnd, pws->p_aop->uMsg, ipack.lParam ); |
| #endif |
| PostMessage16(pws->p_aop->hWnd, pws->p_aop->uMsg, |
| (WPARAM16)ipack.wParam, (LPARAM)ipack.lParam ); |
| } |
| else fprintf(stderr,"AsyncSelect:stray async_op in socket %04x!\n", ipack.wParam); |
| } |
| else fprintf(stderr,"AsyncSelect:stray socket at %04x!\n", ipack.wParam); |
| } |
| } |
| |
| int notify_client( ws_socket* pws, unsigned flag ) |
| { |
| if( pws->p_aop && ((pws->p_aop->flags & flag) || |
| (flag == WS_FD_CONNECTED && pws->flags & WS_FD_CONNECT)) ) |
| { |
| async_ctl.ip.mtype = MTYPE_PARENT; |
| async_ctl.ip.lParam = flag; |
| while( msgsnd(async_qid, (struct msgbuf*)&(async_ctl.ip), |
| MTYPE_PARENT_SIZE, 0) == -1 ) |
| { |
| if( errno == EINTR ) continue; |
| else |
| { |
| perror("AsyncSelect(parent)"); |
| cancel_async_select(pws); |
| pws->flags &= WS_FD_INTERNAL; |
| return 0; |
| } |
| } |
| kill(pws->p_aop->pid, SIGUSR1); |
| return 1; |
| } |
| return 0; |
| } |
| |
| INT16 init_async_select(ws_socket* pws, HWND16 hWnd, UINT16 uMsg, UINT32 lEvent) |
| { |
| ws_async_op* p_aop; |
| |
| if( cancel_async_select(pws) ) /* delete old async handler if any */ |
| pws->flags &= WS_FD_INTERNAL; |
| |
| if( lEvent == 0 ) return 0; |
| |
| /* setup async handler - some data may be redundant */ |
| |
| WINSOCK_unblock_io(pws->fd, 1); |
| if( (p_aop = (ws_async_op*)WS_ALLOC(sizeof(ws_async_op))) ) |
| { |
| p_aop->hWnd = hWnd; |
| p_aop->uMsg = uMsg; |
| pws->p_aop = p_aop; |
| |
| async_ctl.lEvent = p_aop->flags = lEvent; |
| async_ctl.ws_sock = pws; |
| async_ctl.ip.wParam = (UINT16)WS_PTR2HANDLE(pws); |
| async_ctl.ip.lParam = 0; |
| |
| p_aop->pid = fork(); |
| if( p_aop->pid != -1 ) |
| if( p_aop->pid == 0 ) WINSOCK_do_async_select(); /* child process */ |
| else pws->flags |= lEvent; |
| |
| signal( SIGUSR1, _sigusr1_handler_parent ); |
| return 0; /* Wine process */ |
| } |
| return SOCKET_ERROR; |
| } |
| |
| INT16 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) ) |
| if( init_async_select(pws, hWnd, uMsg, lEvent) == 0 ) return 0; |
| else pwsi->err = WSAENOBUFS; |
| return SOCKET_ERROR; |
| } |
| |
| /* ----- miscellaneous */ |
| |
| INT16 __WSAFDIsSet(SOCKET16 fd, ws_fd_set *set) |
| { |
| int i = set->fd_count; |
| |
| dprintf_winsock(stddeb, "__WSAFDIsSet(%d,%8lx)\n",fd,(unsigned long)set); |
| |
| while (i--) |
| if (set->fd_array[i] == fd) return 1; |
| return 0; |
| } |
| |
| BOOL16 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; |
| } |
| |
| INT16 WSACancelBlockingCall(void) |
| { |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WS_CancelBlockingCall(%08x)\n", (unsigned)pwsi); |
| |
| if( pwsi ) return 0; |
| return SOCKET_ERROR; |
| } |
| |
| FARPROC16 WSASetBlockingHook(FARPROC16 lpBlockFunc) |
| { |
| FARPROC16 prev; |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WS_SetBlockingHook(%08x): hook %08x\n", |
| (unsigned)pwsi, (unsigned) lpBlockFunc); |
| |
| if( pwsi ) { |
| prev = pwsi->blocking_hook; |
| pwsi->blocking_hook = lpBlockFunc; |
| return prev; |
| } |
| return 0; |
| } |
| |
| INT16 WSAUnhookBlockingHook(void) |
| { |
| LPWSINFO pwsi = wsi_find(GetCurrentTask()); |
| |
| dprintf_winsock(stddeb, "WS_UnhookBlockingHook(%08x)\n", (unsigned)pwsi); |
| if( pwsi ) return (INT16)(INT32)(pwsi->blocking_hook = (FARPROC16)NULL); |
| return SOCKET_ERROR; |
| } |
| |
| VOID |
| 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;i<j;i++) |
| { l_to[i] = base + (p - ref); |
| k = ( item_size ) ? item_size : strlen(l_src[i]) + 1; |
| memcpy(p, l_src[i], k); p += k; } |
| l_to[i] = NULL; |
| return (p - ref); |
| } |
| |
| /* ----- hostent */ |
| |
| static int hostent_size(struct hostent* p_he) |
| { |
| int size = 0; |
| if( p_he ) |
| { size = sizeof(struct hostent); |
| size += strlen(p_he->h_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 0 depending on "flag" value. Return data size (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_SEGPTR) ? sizeof(struct ws_hostent) : sizeof(struct 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_SEGPTR) ) |
| { 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; |
| } |
| |
| void fixup_wshe(struct ws_hostent* p_wshe, SEGPTR base) |
| { |
| /* add 'base' to ws_hostent pointers to convert them from offsets */ |
| |
| int i; |
| unsigned* p_aliases,*p_addr; |
| |
| p_aliases = (unsigned*)((char*)p_wshe + (unsigned)p_wshe->h_aliases); |
| p_addr = (unsigned*)((char*)p_wshe + (unsigned)p_wshe->h_addr_list); |
| ((unsigned)(p_wshe->h_name)) += (unsigned)base; |
| ((unsigned)(p_wshe->h_aliases)) += (unsigned)base; |
| ((unsigned)(p_wshe->h_addr_list)) += (unsigned)base; |
| for(i=0;p_aliases[i];i++) p_aliases[i] += (unsigned)base; |
| for(i=0;p_addr[i];i++) p_addr[i] += (unsigned)base; |
| } |
| |
| /* ----- 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_SEGPTR)? sizeof(struct ws_protoent) : sizeof(struct 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; |
| } |
| |
| void fixup_wspe(struct ws_protoent* p_wspe, SEGPTR base) |
| { |
| int i; |
| unsigned* p_aliases = (unsigned*)((char*)p_wspe + (unsigned)p_wspe->p_aliases); |
| ((unsigned)(p_wspe->p_name)) += (unsigned)base; |
| ((unsigned)(p_wspe->p_aliases)) += (unsigned)base; |
| for(i=0;p_aliases[i];i++) p_aliases[i] += (unsigned)base; |
| } |
| |
| /* ----- 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_SEGPTR)? sizeof(struct ws_servent) : sizeof(struct 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_SEGPTR) ) |
| { 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; |
| } |
| |
| void fixup_wsse(struct ws_servent* p_wsse, SEGPTR base) |
| { |
| int i; |
| unsigned* p_aliases = (unsigned*)((char*)p_wsse + (unsigned)p_wsse->s_aliases); |
| ((unsigned)(p_wsse->s_name)) += (unsigned)base; |
| ((p_wsse->s_proto)) += (unsigned)base; |
| ((p_wsse->s_aliases)) += (unsigned)base; |
| for(i=0;p_aliases[i];i++) p_aliases[i] += (unsigned)base; |
| } |
| |
| /* ----------------------------------- 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; |
| } |
| } |
| |
| |