ssize_t sendmsg(int s, const struct msghdr* message, int fl) { SOCKET h = fd_to_socket(s); // Don't currently support the name translation. if (message->msg_name != nullptr || message->msg_namelen != 0) { return (ssize_t)-1; } WSAMSG msg; msg.name = nullptr; msg.namelen = 0; msg.Control.buf = (CHAR*)message->msg_control; msg.Control.len = (ULONG)message->msg_controllen; msg.dwFlags = 0; msg.dwBufferCount = (DWORD)message->msg_iovlen; msg.lpBuffers = new WSABUF[message->msg_iovlen]; SCOPE_EXIT { delete[] msg.lpBuffers; }; for (size_t i = 0; i < message->msg_iovlen; i++) { msg.lpBuffers[i].buf = (CHAR*)message->msg_iov[i].iov_base; msg.lpBuffers[i].len = (ULONG)message->msg_iov[i].iov_len; } DWORD bytesSent; int res = WSASendMsg(h, &msg, 0, &bytesSent, nullptr, nullptr); return res == 0 ? (ssize_t)bytesSent : -1; }
int poll(struct pollfd fds[], nfds_t nfds, int timeout) { // TODO: Allow both file descriptors and SOCKETs in this. for (int i = 0; i < nfds; i++) { fds[i].fd = fd_to_socket(fds[i].fd); } return ::WSAPoll(fds, (ULONG)nfds, timeout); }
ssize_t sendmsg(int s, const struct msghdr* message, int /* flags */) { SOCKET h = fd_to_socket(s); // Unfortunately, WSASendMsg requires the socket to have been opened // as either SOCK_DGRAM or SOCK_RAW, but sendmsg has no such requirement, // so we have to implement it based on send instead :( ssize_t bytesSent = 0; for (size_t i = 0; i < message->msg_iovlen; i++) { int r = -1; if (message->msg_name != nullptr) { r = ::sendto( h, (const char*)message->msg_iov[i].iov_base, (int)message->msg_iov[i].iov_len, message->msg_flags, (const sockaddr*)message->msg_name, (int)message->msg_namelen); } else { r = ::send( h, (const char*)message->msg_iov[i].iov_base, (int)message->msg_iov[i].iov_len, message->msg_flags); } if (r == -1 || size_t(r) != message->msg_iov[i].iov_len) { errno = translate_wsa_error(WSAGetLastError()); if (WSAGetLastError() == WSAEWOULDBLOCK && bytesSent > 0) { return bytesSent; } return -1; } bytesSent += r; } return bytesSent; }
ssize_t recvfrom( int s, void* buf, size_t len, int flags, struct sockaddr* from, socklen_t* fromlen) { if ((flags & MSG_TRUNC) == MSG_TRUNC) { SOCKET h = fd_to_socket(s); WSABUF wBuf{}; wBuf.buf = (CHAR*)buf; wBuf.len = (ULONG)len; WSAMSG wMsg{}; wMsg.dwBufferCount = 1; wMsg.lpBuffers = &wBuf; wMsg.name = from; if (fromlen != nullptr) { wMsg.namelen = *fromlen; } // WSARecvMsg is an extension, so we don't get // the convenience of being able to call it directly, even though // WSASendMsg is part of the normal API -_-... LPFN_WSARECVMSG WSARecvMsg; GUID WSARecgMsg_GUID = WSAID_WSARECVMSG; DWORD recMsgBytes; WSAIoctl( h, SIO_GET_EXTENSION_FUNCTION_POINTER, &WSARecgMsg_GUID, sizeof(WSARecgMsg_GUID), &WSARecvMsg, sizeof(WSARecvMsg), &recMsgBytes, nullptr, nullptr); DWORD bytesReceived; int res = WSARecvMsg(h, &wMsg, &bytesReceived, nullptr, nullptr); errno = translate_wsa_error(WSAGetLastError()); if (res == 0) { return bytesReceived; } if (fromlen != nullptr) { *fromlen = wMsg.namelen; } if ((wMsg.dwFlags & MSG_TRUNC) == MSG_TRUNC) { return wBuf.len + 1; } return -1; } return wrapSocketFunction<ssize_t>( ::recvfrom, s, (char*)buf, (int)len, flags, from, (int*)fromlen); }
ssize_t recv(int s, void* buf, size_t len, int flags) { if ((flags & MSG_DONTWAIT) == MSG_DONTWAIT) { flags &= ~MSG_DONTWAIT; u_long pendingRead = 0; if (ioctlsocket(fd_to_socket(s), FIONREAD, &pendingRead)) { errno = translate_wsa_error(WSAGetLastError()); return -1; } fd_set readSet; FD_ZERO(&readSet); FD_SET(fd_to_socket(s), &readSet); timeval timeout{0, 0}; auto ret = select(1, &readSet, nullptr, nullptr, &timeout); if (ret == 0) { errno = EWOULDBLOCK; return -1; } } return wrapSocketFunction<ssize_t>(::recv, s, (char*)buf, (int)len, flags); }
ssize_t recvmsg(int s, struct msghdr* message, int /* flags */) { SOCKET h = fd_to_socket(s); // Don't currently support the name translation. if (message->msg_name != nullptr || message->msg_namelen != 0) { return (ssize_t)-1; } WSAMSG msg; msg.name = nullptr; msg.namelen = 0; msg.Control.buf = (CHAR*)message->msg_control; msg.Control.len = (ULONG)message->msg_controllen; msg.dwFlags = 0; msg.dwBufferCount = (DWORD)message->msg_iovlen; msg.lpBuffers = new WSABUF[message->msg_iovlen]; SCOPE_EXIT { delete[] msg.lpBuffers; }; for (size_t i = 0; i < message->msg_iovlen; i++) { msg.lpBuffers[i].buf = (CHAR*)message->msg_iov[i].iov_base; msg.lpBuffers[i].len = (ULONG)message->msg_iov[i].iov_len; } // WSARecvMsg is an extension, so we don't get // the convenience of being able to call it directly, even though // WSASendMsg is part of the normal API -_-... LPFN_WSARECVMSG WSARecvMsg; GUID WSARecgMsg_GUID = WSAID_WSARECVMSG; DWORD recMsgBytes; WSAIoctl( h, SIO_GET_EXTENSION_FUNCTION_POINTER, &WSARecgMsg_GUID, sizeof(WSARecgMsg_GUID), &WSARecvMsg, sizeof(WSARecvMsg), &recMsgBytes, nullptr, nullptr); DWORD bytesReceived; int res = WSARecvMsg(h, &msg, &bytesReceived, nullptr, nullptr); errno = translate_wsa_error(WSAGetLastError()); return res == 0 ? (ssize_t)bytesReceived : -1; }
static R wrapSocketFunction(F f, int s, Args... args) { SOCKET h = fd_to_socket(s); R ret = f(h, args...); errno = WSAGetLastError(); return ret; }