7 // helper: convert WSAGetLastError() to an errno constant
8 static int wsa_errno(void)
10 switch(WSAGetLastError()) {
11 case WSAEACCES: return EACCES;
12 case WSAECONNRESET: return ECONNRESET;
13 case WSAEFAULT: return EFAULT;
14 case WSAEINPROGRESS: return EINPROGRESS;
15 case WSAEINTR: return EINTR;
16 case WSAEINVAL: return EINVAL;
17 case WSAEMSGSIZE: return EMSGSIZE;
18 case WSAENETDOWN: return ENETDOWN;
19 case WSAENETRESET: return ENETRESET;
20 case WSAENOBUFS: return ENOBUFS;
21 case WSAENOTCONN: return ENOTCONN;
22 case WSAENOTSOCK: return ENOTSOCK;
23 case WSAEOPNOTSUPP: return EOPNOTSUPP;
24 case WSAESHUTDOWN: return ESHUTDOWN;
25 case WSAETIMEDOUT: return ETIMEDOUT;
26 case WSAEWOULDBLOCK: return EWOULDBLOCK;
32 ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
34 LPFN_WSARECVMSG WSARecvMsg = NULL;
35 GUID wsaid = WSAID_WSARECVMSG;
43 // size_t is larger than DWORD on 64bit
44 if(msg->msg_iovlen > UINT32_MAX) {
49 // obtain the function pointer to WSARecvMsg
50 r = WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
51 &wsaid, sizeof(wsaid), &WSARecvMsg, sizeof(WSARecvMsg),
53 if(r == SOCKET_ERROR) {
57 assert(b == sizeof(WSARecvMsg));
58 assert(WSARecvMsg != NULL);
60 // convert msghdr to WSAMSG structure
61 wsamsg.name = msg->msg_name;
62 wsamsg.namelen = msg->msg_namelen;
63 wsamsg.lpBuffers = malloc(msg->msg_iovlen * sizeof(WSABUF));
64 wsamsg.dwBufferCount = msg->msg_iovlen;
65 wsamsg.Control.len = msg->msg_controllen;
66 wsamsg.Control.buf = msg->msg_control;
67 wsamsg.dwFlags = (DWORD)flags;
69 // all flags that fit into dwFlags also fit through the flags argument
70 assert(sizeof(DWORD) <= sizeof(flags));
72 if(wsamsg.lpBuffers == NULL) {
73 // malloc will have set errno
77 // re-wrap iovecs as WSABUFs
78 for(i=0; i<msg->msg_iovlen; i++) {
80 if(msg->msg_iov[i].iov_len > ULONG_MAX) {
81 free(wsamsg.lpBuffers);
86 wsamsg.lpBuffers[i].len = msg->msg_iov[i].iov_len;
87 wsamsg.lpBuffers[i].buf = msg->msg_iov[i].iov_base;
90 r = WSARecvMsg(sockfd, &wsamsg, &bytesrcvd, NULL, NULL);
92 // the allocated WSABUF wrappers are no longer needed
93 free(wsamsg.lpBuffers);
95 if(r == SOCKET_ERROR) {
96 // XXX do we need special handling for ENETRESET, EMSGSIZE, ETIMEDOUT?
101 // DWORD has one bit more than ssize_t on 32bit
102 // XXX check for this condition before the WSARecvMsg call
103 if(bytesrcvd > SSIZE_MAX) {
108 // transfer results from wsamsg to msg
109 // NB: the data and control buffers are shared
110 msg->msg_controllen = wsamsg.Control.len;
111 msg->msg_flags = (int)wsamsg.dwFlags;
112 // all flags that fit into dwFlags also fit into msg_flags (see above)
117 ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
119 LPFN_WSASENDMSG WSASendMsg = NULL;
120 GUID wsaid = WSAID_WSASENDMSG;
128 // size_t is larger than DWORD on 64bit
129 if(msg->msg_iovlen > UINT32_MAX) {
134 // obtain the function pointer to WSASendMsg
135 r = WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
136 &wsaid, sizeof(wsaid), &WSASendMsg, sizeof(WSASendMsg),
138 if(r == SOCKET_ERROR) {
142 assert(b == sizeof(WSASendMsg));
143 assert(WSASendMsg != NULL);
145 // convert msghdr to WSAMSG structure
146 wsamsg.name = msg->msg_name;
147 wsamsg.namelen = msg->msg_namelen;
148 wsamsg.lpBuffers = malloc(msg->msg_iovlen * sizeof(WSABUF));
149 wsamsg.dwBufferCount = msg->msg_iovlen;
150 wsamsg.Control.len = msg->msg_controllen;
151 wsamsg.Control.buf = msg->msg_control;
152 wsamsg.dwFlags = 0; // ignored
154 if(wsamsg.lpBuffers == NULL) {
155 // malloc will have set errno
159 // re-wrap iovecs as WSABUFs
160 for(i=0; i<msg->msg_iovlen; i++) {
162 if(msg->msg_iov[i].iov_len > ULONG_MAX) {
163 free(wsamsg.lpBuffers);
168 wsamsg.lpBuffers[i].len = msg->msg_iov[i].iov_len;
169 wsamsg.lpBuffers[i].buf = msg->msg_iov[i].iov_base;
172 r = WSASendMsg(sockfd, &wsamsg, flags, &bytessent, NULL, NULL);
174 // the allocated WSABUF wrappers are no longer needed
175 free(wsamsg.lpBuffers);
177 if(r == SOCKET_ERROR) {
178 // XXX do we need special handling for ENETRESET, ETIMEDOUT?
183 // DWORD has one bit more than ssize_t on 32bit
184 // XXX check for this condition before sending anything
185 if(bytessent > SSIZE_MAX) {
193 int ioctl(int d, unsigned long request, int *p)
197 if(ioctlsocket(d, request, &arg) == SOCKET_ERROR) {
211 int pipe(int pipefd[2])
213 int lsock = INVALID_SOCKET;
214 struct sockaddr_in laddr;
215 socklen_t laddrlen = sizeof(laddr);
217 pipefd[0] = pipefd[1] = INVALID_SOCKET;
219 // bind a listening socket to a TCP port on localhost
220 laddr.sin_family = AF_INET;
222 laddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
223 if((lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
225 if(bind(lsock, (struct sockaddr *)&laddr, sizeof(laddr)) == SOCKET_ERROR)
227 if(listen(lsock, 1) == SOCKET_ERROR)
230 // determine which address (i.e. port) we got bound to
231 if(getsockname(lsock, (struct sockaddr *)&laddr, &laddrlen) == SOCKET_ERROR)
233 assert(laddrlen == sizeof(laddr));
234 laddr.sin_family = AF_INET;
235 laddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
237 // connect and accept
238 if((pipefd[0] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
240 if(connect(pipefd[0], (const struct sockaddr *)&laddr, sizeof(laddr)) == SOCKET_ERROR)
242 if((pipefd[1] = accept(lsock, NULL, NULL)) == SOCKET_ERROR)
245 // close the listener
252 closesocket(pipefd[0]);
257 int uname(struct utsname *buf)
260 const char *arch = "unknown";
262 memset(buf, 0, sizeof(struct utsname));
265 strncpy(buf->sysname, "Windows", sizeof(buf->sysname)-1);
266 strncpy(buf->release, "unknown", sizeof(buf->sysname)-1); // we don't need it
267 strncpy(buf->version, "unknown", sizeof(buf->sysname)-1); // we don't need it
269 // computer (node) name
270 if(GetComputerName(buf->nodename, sizeof(buf->nodename)-1) == 0) {
277 switch(si.wProcessorArchitecture) {
278 case PROCESSOR_ARCHITECTURE_AMD64: arch = "amd64"; break;
279 case PROCESSOR_ARCHITECTURE_ARM: arch = "arm"; break;
280 case PROCESSOR_ARCHITECTURE_IA64: arch = "ia64"; break;
281 case PROCESSOR_ARCHITECTURE_INTEL: arch = "x86"; break;
282 default: arch = "unknown";
284 strncpy(buf->machine, arch, sizeof(buf->machine)-1);