int rpl_setsockopt (int fd, int level, int optname, const void *optval, socklen_t optlen) { SOCKET sock = FD_TO_SOCKET (fd); int r; if (sock == INVALID_SOCKET) { errno = EBADF; return -1; } else { if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) { const struct timeval *tv = optval; int milliseconds = tv->tv_sec * 1000 + tv->tv_usec / 1000; optval = &milliseconds; r = setsockopt (sock, level, optname, optval, sizeof (int)); } else { r = setsockopt (sock, level, optname, optval, optlen); } if (r < 0) set_winsock_errno (); return r; } }
static int ioctl_fd_maybe_socket (const struct fd_hook *remaining_list, gl_ioctl_fn primary, int fd, int request, void *arg) { SOCKET sock; WSANETWORKEVENTS ev; /* Test whether fd refers to a socket. */ sock = FD_TO_SOCKET (fd); ev.lNetworkEvents = 0xDEADBEEF; WSAEnumNetworkEvents (sock, NULL, &ev); if (ev.lNetworkEvents != 0xDEADBEEF) { /* fd refers to a socket. */ if (ioctlsocket (sock, request, arg) < 0) { set_winsock_errno (); return -1; } else return 0; } else /* Some other type of file descriptor. */ return execute_ioctl_hooks (remaining_list, primary, fd, request, arg); }
int rpl_shutdown (int fd, int how) { SOCKET sock = FD_TO_SOCKET (fd); int r = shutdown (sock, how); if (r < 0) set_winsock_errno (); return r; }
int rpl_getpeername (int fd, struct sockaddr *addr, socklen_t *addrlen) { SOCKET sock = FD_TO_SOCKET (fd); int r = getpeername (sock, addr, addrlen); if (r < 0) set_winsock_errno (); return r; }
ssize_t rpl_send (int fd, const void *buf, size_t len, int flags) { SOCKET sock = FD_TO_SOCKET (fd); int r = send (sock, buf, len, flags); if (r < 0) set_winsock_errno (); return r; }
int rpl_bind (int fd, struct sockaddr *sockaddr, int len) { SOCKET sock = FD_TO_SOCKET (fd); int r = bind (sock, sockaddr, len); if (r < 0) set_winsock_errno (); return r; }
int rpl_listen (int fd, int backlog) { SOCKET sock = FD_TO_SOCKET (fd); int r = listen (sock, backlog); if (r < 0) set_winsock_errno (); return r; }
int rpl_gethostname (char *name, size_t len) { int r; if (len > INT_MAX) len = INT_MAX; gl_sockets_startup (SOCKETS_1_1); r = gethostname (name, (int) len); if (r < 0) set_winsock_errno (); return r; }
int rpl_socket (int domain, int type, int protocol) { /* We have to use WSASocket() to create non-overlapped IO sockets. Overlapped IO sockets cannot be used with read/write. */ SOCKET fh = WSASocket (domain, type, protocol, NULL, 0, 0); if (fh == INVALID_SOCKET) { set_winsock_errno (); return -1; } else return SOCKET_TO_FD (fh); }
int rpl_connect (int fd, struct sockaddr *sockaddr, int len) { SOCKET sock = FD_TO_SOCKET (fd); int r = connect (sock, sockaddr, len); if (r < 0) { /* EINPROGRESS is not returned by WinSock 2.0; for backwards compatibility, connect(2) uses EWOULDBLOCK. */ if (WSAGetLastError () == WSAEWOULDBLOCK) WSASetLastError (WSAEINPROGRESS); set_winsock_errno (); } return r; }
ssize_t rpl_recvfrom (int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { int frombufsize = (from != NULL ? *fromlen : 0); SOCKET sock = FD_TO_SOCKET (fd); int r = recvfrom (sock, buf, len, flags, from, fromlen); if (r < 0) set_winsock_errno (); /* Winsock recvfrom() only returns a valid 'from' when the socket is connectionless. POSIX gives a valid 'from' for all types of sockets. */ else if (from != NULL && *fromlen == frombufsize) rpl_getpeername (fd, from, fromlen); return r; }
int rpl_getpeername (int fd, struct sockaddr *addr, socklen_t *addrlen) { SOCKET sock = FD_TO_SOCKET (fd); if (sock == INVALID_SOCKET) { errno = EBADF; return -1; } else { int r = getpeername (sock, addr, addrlen); if (r < 0) set_winsock_errno (); return r; } }
int rpl_ioctl (int fd, int req, ...) { void *buf; va_list args; SOCKET sock; int r; va_start (args, req); buf = va_arg (args, void *); va_end (args); sock = FD_TO_SOCKET (fd); r = ioctlsocket (sock, req, buf); if (r < 0) set_winsock_errno (); return r; }
ssize_t rpl_send (int fd, const void *buf, size_t len, int flags) { SOCKET sock = FD_TO_SOCKET (fd); if (sock == INVALID_SOCKET) { errno = EBADF; return -1; } else { int r = send (sock, buf, len, flags); if (r < 0) set_winsock_errno (); return r; } }
int rpl_getsockopt (int fd, int level, int optname, void *optval, socklen_t *optlen) { SOCKET sock = FD_TO_SOCKET (fd); if (sock == INVALID_SOCKET) { errno = EBADF; return -1; } else { int r; if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) { int milliseconds; int milliseconds_len = sizeof (int); struct timeval tv; size_t n; r = getsockopt (sock, level, optname, (char *) &milliseconds, &milliseconds_len); tv.tv_sec = milliseconds / 1000; tv.tv_usec = (milliseconds - 1000 * tv.tv_sec) * 1000; n = sizeof (struct timeval); if (n > *optlen) n = *optlen; memcpy (optval, &tv, n); *optlen = n; } else { r = getsockopt (sock, level, optname, optval, optlen); } if (r < 0) set_winsock_errno (); return r; } }
int rpl_listen (int fd, int backlog) { SOCKET sock = FD_TO_SOCKET (fd); if (sock == INVALID_SOCKET) { errno = EBADF; return -1; } else { int r = listen (sock, backlog); if (r < 0) set_winsock_errno (); return r; } }
int rpl_bind (int fd, const struct sockaddr *sockaddr, socklen_t len) { SOCKET sock = FD_TO_SOCKET (fd); if (sock == INVALID_SOCKET) { errno = EBADF; return -1; } else { int r = bind (sock, sockaddr, len); if (r < 0) set_winsock_errno (); return r; } }
int rpl_shutdown (int fd, int how) { SOCKET sock = FD_TO_SOCKET (fd); if (sock == INVALID_SOCKET) { errno = EBADF; return -1; } else { int r = shutdown (sock, how); if (r < 0) set_winsock_errno (); return r; } }
ssize_t rpl_sendto (int fd, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { SOCKET sock = FD_TO_SOCKET (fd); if (sock == INVALID_SOCKET) { errno = EBADF; return -1; } else { int r = sendto (sock, buf, len, flags, to, tolen); if (r < 0) set_winsock_errno (); return r; } }
static int close_fd_maybe_socket (const struct fd_hook *remaining_list, gl_close_fn primary, int fd) { /* Note about multithread-safety: There is a race condition where, between our calls to closesocket() and the primary close(), some other thread could make system calls that allocate precisely the same HANDLE value as sock; then the primary close() would call CloseHandle() on it. */ SOCKET sock; WSANETWORKEVENTS ev; /* Test whether fd refers to a socket. */ sock = FD_TO_SOCKET (fd); ev.lNetworkEvents = 0xDEADBEEF; WSAEnumNetworkEvents (sock, NULL, &ev); if (ev.lNetworkEvents != 0xDEADBEEF) { /* fd refers to a socket. */ /* FIXME: other applications, like squid, use an undocumented _free_osfhnd free function. But this is not enough: The 'osfile' flags for fd also needs to be cleared, but it is hard to access it. Instead, here we just close twice the file descriptor. */ if (closesocket (sock)) { set_winsock_errno (); return -1; } else { /* This call frees the file descriptor and does a CloseHandle ((HANDLE) _get_osfhandle (fd)), which fails. */ _close (fd); return 0; } } else /* Some other type of file descriptor. */ return execute_close_hooks (remaining_list, primary, fd); }
int rpl_accept (int fd, struct sockaddr *addr, socklen_t *addrlen) { SOCKET sock = FD_TO_SOCKET (fd); if (sock == INVALID_SOCKET) { errno = EBADF; return -1; } else { SOCKET fh = accept (sock, addr, addrlen); if (fh == INVALID_SOCKET) { set_winsock_errno (); return -1; } else return SOCKET_TO_FD (fh); } }