]> git.meshlink.io Git - catta/blob - src/compat/windows/wincompat.c
add (untested) implementation of recvmsg in terms of WSARecvMsg
[catta] / src / compat / windows / wincompat.c
1 #include "wincompat.h"
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <assert.h>
5 #include <stdint.h>
6
7 // helper: convert WSAGetLastError() to an errno constant
8 static int wsa_errno(void)
9 {
10     switch(WSAGetLastError()) {
11         case WSAECONNRESET:     return ECONNRESET;
12         case WSAEFAULT:         return EFAULT;
13         case WSAEINPROGRESS:    return EINPROGRESS;
14         case WSAEINTR:          return EINTR;
15         case WSAEINVAL:         return EINVAL;
16         case WSAEMSGSIZE:       return EMSGSIZE;
17         case WSAENETDOWN:       return ENETDOWN;
18         case WSAENETRESET:      return ENETRESET;
19         case WSAENOTCONN:       return ENOTCONN;
20         case WSAENOTSOCK:       return ENOTSOCK;
21         case WSAEOPNOTSUPP:     return EOPNOTSUPP;
22         case WSAEWOULDBLOCK:    return EWOULDBLOCK;
23         default:
24             return EINVAL;
25     }
26 }
27
28 ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
29 {
30     LPFN_WSARECVMSG WSARecvMsg = NULL;
31     GUID wsaid = WSAID_WSARECVMSG;
32     DWORD b;
33
34     DWORD bytesrcvd;
35     WSAMSG wsamsg;
36     size_t i;
37     int r;
38
39     // size_t is larger than DWORD on 64bit
40     if(msg->msg_iovlen > UINT32_MAX) {
41         errno = EINVAL;
42         return -1;
43     }
44
45     // obtain the function pointer to WSARecvMsg
46     r = WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
47                  &wsaid, sizeof(wsaid), &WSARecvMsg, sizeof(WSARecvMsg),
48                  &b, NULL, NULL);
49     if(r == SOCKET_ERROR) {
50         errno = wsa_errno();
51         return -1;
52     }
53     assert(b == sizeof(WSARecvMsg));
54     assert(WSARecvMsg != NULL);
55
56     // convert msghdr to WSAMSG structure
57     wsamsg.name = msg->msg_name;
58     wsamsg.namelen = msg->msg_namelen;
59     wsamsg.lpBuffers = malloc(msg->msg_iovlen * sizeof(WSABUF));
60     wsamsg.dwBufferCount = msg->msg_iovlen;
61     wsamsg.Control.len = msg->msg_controllen;
62     wsamsg.Control.buf = msg->msg_control;
63     wsamsg.dwFlags = (DWORD)flags;
64
65     // all flags that fit into dwFlags also fit through the flags argument
66     assert(sizeof(DWORD) <= sizeof(flags));
67
68     if(wsamsg.lpBuffers == NULL) {
69         // malloc will have set errno
70         return -1;
71     }
72
73     // re-wrap iovecs as WSABUFs
74     for(i=0; i<msg->msg_iovlen; i++) {
75         // size_t vs. u_long
76         if(msg->msg_iov[i].iov_len > ULONG_MAX) {
77             free(wsamsg.lpBuffers);
78             errno = EINVAL;
79             return -1;
80         }
81
82         wsamsg.lpBuffers[i].len = msg->msg_iov[i].iov_len;
83         wsamsg.lpBuffers[i].buf = msg->msg_iov[i].iov_base;
84     }
85
86     r = WSARecvMsg(sockfd, &wsamsg, &bytesrcvd, NULL, NULL);
87
88     // the allocated WSABUF wrappers are no longer needed
89     free(wsamsg.lpBuffers);
90
91     if(r == SOCKET_ERROR) {
92         // XXX do we need special handling for ENETRESET, EMSGSIZE, ETIMEDOUT?
93         errno = wsa_errno();
94         return -1;
95     }
96
97     // DWORD has one bit more than ssize_t on 32bit
98     if(bytesrcvd > SSIZE_MAX) {
99         errno = EINVAL;
100         return -1;
101     }
102
103     // transfer results from wsamsg to msg
104     // NB: the data and control buffers are shared
105     msg->msg_controllen = wsamsg.Control.len;
106     msg->msg_flags = (int)wsamsg.dwFlags;
107         // all flags that fit into dwFlags also fit into msg_flags (see above)
108
109     return bytesrcvd;
110 }
111
112 int uname(struct utsname *buf)
113 {
114     SYSTEM_INFO si;
115     const char *arch = "unknown";
116
117     memset(buf, 0, sizeof(struct utsname));
118
119     // operating system
120     strncpy(buf->sysname, "Windows", sizeof(buf->sysname)-1);
121     strncpy(buf->release, "unknown", sizeof(buf->sysname)-1);   // we don't need it
122     strncpy(buf->version, "unknown", sizeof(buf->sysname)-1);   // we don't need it
123
124     // computer (node) name
125     if(GetComputerName(buf->nodename, sizeof(buf->nodename)-1) == 0) {
126         errno = EFAULT;
127         return -1;
128     }
129
130     // hardware type
131     GetSystemInfo(&si);
132     switch(si.wProcessorArchitecture) {
133         case PROCESSOR_ARCHITECTURE_AMD64: arch = "amd64"; break;
134         case PROCESSOR_ARCHITECTURE_ARM:   arch = "arm";   break;
135         case PROCESSOR_ARCHITECTURE_IA64:  arch = "ia64";  break;
136         case PROCESSOR_ARCHITECTURE_INTEL: arch = "x86";   break;
137         default: arch = "unknown";
138     }
139     strncpy(buf->machine, arch, sizeof(buf->machine)-1);
140
141     return 0;
142 }