# HG changeset patch # User Jason Rumney # Date 1016656724 0 # Node ID 6e7772d1632eef790739e3a43e22cf0d40c7ffe0 # Parent 134644f9485078c9a79264ab1ce952c4473709fa (init_winsock): Dynamically load new server and UDP socket functions. (socket_to_fd): New function. (sys_socket): Use it. (sys_setsockopt, sys_listen, sys_getsockname, sys_accept) (sys_recvfrom, sys_sendto): New wrapper functions. diff -r 134644f94850 -r 6e7772d1632e src/w32.c --- a/src/w32.c Wed Mar 20 20:37:41 2002 +0000 +++ b/src/w32.c Wed Mar 20 20:38:44 2002 +0000 @@ -85,6 +85,12 @@ #undef gethostbyname #undef getservbyname #undef shutdown +#undef setsockopt +#undef listen +#undef getsockname +#undef accept +#undef recvfrom +#undef sendto #endif #include "w32.h" @@ -2421,7 +2427,18 @@ int (PASCAL *pfn_gethostname) (char * name, int namelen); struct hostent * (PASCAL *pfn_gethostbyname) (const char * name); struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto); - + +int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname, + const char * optval, int optlen); +int (PASCAL *pfn_listen) (SOCKET s, int backlog); +int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name, + int * namelen); +SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen); +int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags, + struct sockaddr * from, int * fromlen); +int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags, + const struct sockaddr * to, int tolen); + /* SetHandleInformation is only needed to make sockets non-inheritable. */ BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags); #ifndef HANDLE_FLAG_INHERIT @@ -2491,7 +2508,12 @@ LOAD_PROC( gethostbyname ); LOAD_PROC( getservbyname ); LOAD_PROC( WSACleanup ); - + LOAD_PROC( setsockopt ); + LOAD_PROC( listen ); + LOAD_PROC( getsockname ); + LOAD_PROC( accept ); + LOAD_PROC( recvfrom ); + LOAD_PROC( sendto ); #undef LOAD_PROC /* specify version 1.1 of winsock */ @@ -2662,12 +2684,12 @@ #define SOCK_HANDLE(fd) ((SOCKET) fd_info[fd].hnd) #endif +int socket_to_fd (SOCKET s); + int sys_socket(int af, int type, int protocol) { - int fd; - long s; - child_process * cp; + SOCKET s; if (winsock_lib == NULL) { @@ -2678,105 +2700,114 @@ check_errno (); /* call the real socket function */ - s = (long) pfn_socket (af, type, protocol); + s = pfn_socket (af, type, protocol); if (s != INVALID_SOCKET) + return socket_to_fd (s); + + set_errno (); + return -1; +} + +/* Convert a SOCKET to a file descriptor. */ +int +socket_to_fd (SOCKET s) +{ + int fd; + child_process * cp; + + /* Although under NT 3.5 _open_osfhandle will accept a socket + handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT, + that does not work under NT 3.1. However, we can get the same + effect by using a backdoor function to replace an existing + descriptor handle with the one we want. */ + + /* allocate a file descriptor (with appropriate flags) */ + fd = _open ("NUL:", _O_RDWR); + if (fd >= 0) { - /* Although under NT 3.5 _open_osfhandle will accept a socket - handle, if opened with SO_OPENTYPE == SO_SYNCHRONOUS_NONALERT, - that does not work under NT 3.1. However, we can get the same - effect by using a backdoor function to replace an existing - descriptor handle with the one we want. */ - - /* allocate a file descriptor (with appropriate flags) */ - fd = _open ("NUL:", _O_RDWR); - if (fd >= 0) - { #ifdef SOCK_REPLACE_HANDLE - /* now replace handle to NUL with our socket handle */ - CloseHandle ((HANDLE) _get_osfhandle (fd)); - _free_osfhnd (fd); - _set_osfhnd (fd, s); - /* setmode (fd, _O_BINARY); */ + /* now replace handle to NUL with our socket handle */ + CloseHandle ((HANDLE) _get_osfhandle (fd)); + _free_osfhnd (fd); + _set_osfhnd (fd, s); + /* setmode (fd, _O_BINARY); */ #else - /* Make a non-inheritable copy of the socket handle. Note - that it is possible that sockets aren't actually kernel - handles, which appears to be the case on Windows 9x when - the MS Proxy winsock client is installed. */ + /* Make a non-inheritable copy of the socket handle. Note + that it is possible that sockets aren't actually kernel + handles, which appears to be the case on Windows 9x when + the MS Proxy winsock client is installed. */ + { + /* Apparently there is a bug in NT 3.51 with some service + packs, which prevents using DuplicateHandle to make a + socket handle non-inheritable (causes WSACleanup to + hang). The work-around is to use SetHandleInformation + instead if it is available and implemented. */ + if (pfn_SetHandleInformation) { - /* Apparently there is a bug in NT 3.51 with some service - packs, which prevents using DuplicateHandle to make a - socket handle non-inheritable (causes WSACleanup to - hang). The work-around is to use SetHandleInformation - instead if it is available and implemented. */ - if (pfn_SetHandleInformation) + pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0); + } + else + { + HANDLE parent = GetCurrentProcess (); + HANDLE new_s = INVALID_HANDLE_VALUE; + + if (DuplicateHandle (parent, + (HANDLE) s, + parent, + &new_s, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) { - pfn_SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0); - } - else - { - HANDLE parent = GetCurrentProcess (); - HANDLE new_s = INVALID_HANDLE_VALUE; - - if (DuplicateHandle (parent, - (HANDLE) s, - parent, - &new_s, - 0, - FALSE, - DUPLICATE_SAME_ACCESS)) + /* It is possible that DuplicateHandle succeeds even + though the socket wasn't really a kernel handle, + because a real handle has the same value. So + test whether the new handle really is a socket. */ + long nonblocking = 0; + if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0) { - /* It is possible that DuplicateHandle succeeds even - though the socket wasn't really a kernel handle, - because a real handle has the same value. So - test whether the new handle really is a socket. */ - long nonblocking = 0; - if (pfn_ioctlsocket ((SOCKET) new_s, FIONBIO, &nonblocking) == 0) - { - pfn_closesocket (s); - s = (SOCKET) new_s; - } - else - { - CloseHandle (new_s); - } - } - } + pfn_closesocket (s); + s = (SOCKET) new_s; + } + else + { + CloseHandle (new_s); + } + } } - fd_info[fd].hnd = (HANDLE) s; + } + fd_info[fd].hnd = (HANDLE) s; #endif - /* set our own internal flags */ - fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE; - - cp = new_child (); - if (cp) + /* set our own internal flags */ + fd_info[fd].flags = FILE_SOCKET | FILE_BINARY | FILE_READ | FILE_WRITE; + + cp = new_child (); + if (cp) + { + cp->fd = fd; + cp->status = STATUS_READ_ACKNOWLEDGED; + + /* attach child_process to fd_info */ + if (fd_info[ fd ].cp != NULL) { - cp->fd = fd; - cp->status = STATUS_READ_ACKNOWLEDGED; - - /* attach child_process to fd_info */ - if (fd_info[ fd ].cp != NULL) - { - DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd)); - abort (); - } - - fd_info[ fd ].cp = cp; - - /* success! */ - winsock_inuse++; /* count open sockets */ - return fd; + DebPrint (("sys_socket: fd_info[%d] apparently in use!\n", fd)); + abort (); } - /* clean up */ - _close (fd); + fd_info[ fd ].cp = cp; + + /* success! */ + winsock_inuse++; /* count open sockets */ + return fd; } - pfn_closesocket (s); - h_errno = EMFILE; + + /* clean up */ + _close (fd); } - set_errno (); - + pfn_closesocket (s); + h_errno = EMFILE; return -1; } @@ -2915,6 +2946,137 @@ return SOCKET_ERROR; } +int +sys_setsockopt (int s, int level, int optname, const char * optval, int optlen) +{ + if (winsock_lib == NULL) + { + h_errno = ENETDOWN; + return SOCKET_ERROR; + } + + check_errno (); + if (fd_info[s].flags & FILE_SOCKET) + { + int rc = pfn_setsockopt (SOCK_HANDLE (s), level, optname, + optval, optlen); + if (rc == SOCKET_ERROR) + set_errno (); + return rc; + } + h_errno = ENOTSOCK; + return SOCKET_ERROR; +} + +int +sys_listen (int s, int backlog) +{ + if (winsock_lib == NULL) + { + h_errno = ENETDOWN; + return SOCKET_ERROR; + } + + check_errno (); + if (fd_info[s].flags & FILE_SOCKET) + { + int rc = pfn_listen (SOCK_HANDLE (s), backlog); + if (rc == SOCKET_ERROR) + set_errno (); + return rc; + } + h_errno = ENOTSOCK; + return SOCKET_ERROR; +} + +int +sys_getsockname (int s, struct sockaddr * name, int * namelen) +{ + if (winsock_lib == NULL) + { + h_errno = ENETDOWN; + return SOCKET_ERROR; + } + + check_errno (); + if (fd_info[s].flags & FILE_SOCKET) + { + int rc = pfn_getsockname (SOCK_HANDLE (s), name, namelen); + if (rc == SOCKET_ERROR) + set_errno (); + return rc; + } + h_errno = ENOTSOCK; + return SOCKET_ERROR; +} + +int +sys_accept (int s, struct sockaddr * addr, int * addrlen) +{ + if (winsock_lib == NULL) + { + h_errno = ENETDOWN; + return -1; + } + + check_errno (); + if (fd_info[s].flags & FILE_SOCKET) + { + SOCKET s = pfn_accept (SOCK_HANDLE (s), addr, addrlen); + if (s != INVALID_SOCKET) + return socket_to_fd (s); + + set_errno (); + return -1; + } + h_errno = ENOTSOCK; + return -1; +} + +int +sys_recvfrom (int s, char * buf, int len, int flags, + struct sockaddr * from, int * fromlen) +{ + if (winsock_lib == NULL) + { + h_errno = ENETDOWN; + return SOCKET_ERROR; + } + + check_errno (); + if (fd_info[s].flags & FILE_SOCKET) + { + int rc = pfn_recvfrom (SOCK_HANDLE (s), buf, len, flags, from, fromlen); + if (rc == SOCKET_ERROR) + set_errno (); + return rc; + } + h_errno = ENOTSOCK; + return SOCKET_ERROR; +} + +int +sys_sendto (int s, const char * buf, int len, int flags, + const struct sockaddr * to, int tolen) +{ + if (winsock_lib == NULL) + { + h_errno = ENETDOWN; + return SOCKET_ERROR; + } + + check_errno (); + if (fd_info[s].flags & FILE_SOCKET) + { + int rc = pfn_sendto (SOCK_HANDLE (s), buf, len, flags, to, tolen); + if (rc == SOCKET_ERROR) + set_errno (); + return rc; + } + h_errno = ENOTSOCK; + return SOCKET_ERROR; +} + #endif /* HAVE_SOCKETS */