9 // helper: convert WSAGetLastError() to an errno constant
10 static int wsa_errno(void)
12 switch(WSAGetLastError()) {
13 case WSAEACCES: return EACCES;
14 case WSAECONNRESET: return ECONNRESET;
15 case WSAEFAULT: return EFAULT;
16 case WSAEINPROGRESS: return EINPROGRESS;
17 case WSAEINTR: return EINTR;
18 case WSAEINVAL: return EINVAL;
19 case WSAEMSGSIZE: return EMSGSIZE;
20 case WSAENETDOWN: return ENETDOWN;
21 case WSAENETRESET: return ENETRESET;
22 case WSAENOBUFS: return ENOBUFS;
23 case WSAENOTCONN: return ENOTCONN;
24 case WSAENOTSOCK: return ENOTSOCK;
25 case WSAEOPNOTSUPP: return EOPNOTSUPP;
26 case WSAESHUTDOWN: return ESHUTDOWN;
27 case WSAETIMEDOUT: return ETIMEDOUT;
28 case WSAEWOULDBLOCK: return EWOULDBLOCK;
34 void winsock_init(void)
39 if((error = WSAStartup(MAKEWORD(2,2), &wsa)) != 0)
40 catta_log_error("WSAStartup() failed: %d", error);
43 void winsock_exit(void)
45 if(WSACleanup() == SOCKET_ERROR)
46 catta_log_warn("WSACleanup() failed: %d", WSAGetLastError());
49 char *errnostrsocket(void)
53 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
54 NULL, WSAGetLastError(), 0, buf, sizeof(buf), NULL);
59 ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)
61 LPFN_WSARECVMSG WSARecvMsg = NULL;
62 GUID wsaid = WSAID_WSARECVMSG;
70 // size_t is larger than DWORD on 64bit
71 if(msg->msg_iovlen > UINT32_MAX) {
76 // obtain the function pointer to WSARecvMsg
77 r = WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
78 &wsaid, sizeof(wsaid), &WSARecvMsg, sizeof(WSARecvMsg),
80 if(r == SOCKET_ERROR) {
84 assert(b == sizeof(WSARecvMsg));
85 assert(WSARecvMsg != NULL);
87 // convert msghdr to WSAMSG structure
88 wsamsg.name = msg->msg_name;
89 wsamsg.namelen = msg->msg_namelen;
90 wsamsg.lpBuffers = malloc(msg->msg_iovlen * sizeof(WSABUF));
91 wsamsg.dwBufferCount = msg->msg_iovlen;
92 wsamsg.Control.len = msg->msg_controllen;
93 wsamsg.Control.buf = msg->msg_control;
94 wsamsg.dwFlags = (DWORD)flags;
96 // all flags that fit into dwFlags also fit through the flags argument
97 assert(sizeof(DWORD) <= sizeof(flags));
99 if(wsamsg.lpBuffers == NULL) {
100 // malloc will have set errno
104 // re-wrap iovecs as WSABUFs
105 for(i=0; i<msg->msg_iovlen; i++) {
107 if(msg->msg_iov[i].iov_len > ULONG_MAX) {
108 free(wsamsg.lpBuffers);
113 wsamsg.lpBuffers[i].len = msg->msg_iov[i].iov_len;
114 wsamsg.lpBuffers[i].buf = msg->msg_iov[i].iov_base;
117 r = WSARecvMsg(sockfd, &wsamsg, &bytesrcvd, NULL, NULL);
119 // the allocated WSABUF wrappers are no longer needed
120 free(wsamsg.lpBuffers);
122 if(r == SOCKET_ERROR) {
123 // XXX do we need special handling for ENETRESET, EMSGSIZE, ETIMEDOUT?
128 // DWORD has one bit more than ssize_t on 32bit
129 // XXX check for this condition before the WSARecvMsg call
130 if(bytesrcvd > SSIZE_MAX) {
135 // transfer results from wsamsg to msg
136 // NB: the data and control buffers are shared
137 msg->msg_controllen = wsamsg.Control.len;
138 msg->msg_flags = (int)wsamsg.dwFlags;
139 // all flags that fit into dwFlags also fit into msg_flags (see above)
144 getnameinfo(msg->msg_name, msg->msg_namelen, where, sizeof(where), NULL, 0, NI_NUMERICHOST);
145 catta_log_debug("recvmsg: %u bytes from %s", (unsigned int)bytesrcvd, where);
150 ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
152 LPFN_WSASENDMSG WSASendMsg = NULL;
153 GUID wsaid = WSAID_WSASENDMSG;
161 // size_t is larger than DWORD on 64bit
162 if(msg->msg_iovlen > UINT32_MAX) {
167 // obtain the function pointer to WSASendMsg
168 r = WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
169 &wsaid, sizeof(wsaid), &WSASendMsg, sizeof(WSASendMsg),
171 if(r == SOCKET_ERROR) {
175 assert(b == sizeof(WSASendMsg));
176 assert(WSASendMsg != NULL);
178 // convert msghdr to WSAMSG structure
179 wsamsg.name = msg->msg_name;
180 wsamsg.namelen = msg->msg_namelen;
181 wsamsg.lpBuffers = malloc(msg->msg_iovlen * sizeof(WSABUF));
182 wsamsg.dwBufferCount = msg->msg_iovlen;
183 wsamsg.Control.len = msg->msg_controllen;
184 wsamsg.Control.buf = msg->msg_control;
185 wsamsg.dwFlags = 0; // ignored
187 if(wsamsg.lpBuffers == NULL) {
188 // malloc will have set errno
192 // re-wrap iovecs as WSABUFs
193 for(i=0; i<msg->msg_iovlen; i++) {
195 if(msg->msg_iov[i].iov_len > ULONG_MAX) {
196 free(wsamsg.lpBuffers);
201 wsamsg.lpBuffers[i].len = msg->msg_iov[i].iov_len;
202 wsamsg.lpBuffers[i].buf = msg->msg_iov[i].iov_base;
205 r = WSASendMsg(sockfd, &wsamsg, flags, &bytessent, NULL, NULL);
207 // the allocated WSABUF wrappers are no longer needed
208 free(wsamsg.lpBuffers);
210 if(r == SOCKET_ERROR) {
211 // XXX do we need special handling for ENETRESET, ETIMEDOUT?
216 // DWORD has one bit more than ssize_t on 32bit
217 // XXX check for this condition before sending anything
218 if(bytessent > SSIZE_MAX) {
226 getnameinfo(msg->msg_name, msg->msg_namelen, where, sizeof(where), NULL, 0, NI_NUMERICHOST);
227 catta_log_debug("sendmsg: %u bytes to %s", (unsigned int)bytessent, where);
232 int ioctl(int d, unsigned long request, int *p)
236 if(ioctlsocket(d, request, &arg) == SOCKET_ERROR) {
250 int pipe(int pipefd[2])
252 int lsock = INVALID_SOCKET;
253 struct sockaddr_in laddr;
254 socklen_t laddrlen = sizeof(laddr);
256 pipefd[0] = pipefd[1] = INVALID_SOCKET;
258 // bind a listening socket to a TCP port on localhost
259 laddr.sin_family = AF_INET;
261 laddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
262 if((lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
264 if(bind(lsock, (struct sockaddr *)&laddr, sizeof(laddr)) == SOCKET_ERROR)
266 if(listen(lsock, 1) == SOCKET_ERROR)
269 // determine which address (i.e. port) we got bound to
270 if(getsockname(lsock, (struct sockaddr *)&laddr, &laddrlen) == SOCKET_ERROR)
272 assert(laddrlen == sizeof(laddr));
273 laddr.sin_family = AF_INET;
274 laddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
276 // connect and accept
277 if((pipefd[0] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
279 if(connect(pipefd[0], (const struct sockaddr *)&laddr, sizeof(laddr)) == SOCKET_ERROR)
281 if((pipefd[1] = accept(lsock, NULL, NULL)) == SOCKET_ERROR)
284 // close the listener
291 closesocket(pipefd[0]);
296 int uname(struct utsname *buf)
299 const char *arch = "unknown";
301 memset(buf, 0, sizeof(struct utsname));
304 strncpy(buf->sysname, "Windows", sizeof(buf->sysname)-1);
305 strncpy(buf->release, "unknown", sizeof(buf->sysname)-1); // we don't need it
306 strncpy(buf->version, "unknown", sizeof(buf->sysname)-1); // we don't need it
308 // computer (node) name
309 if(GetComputerName(buf->nodename, sizeof(buf->nodename)-1) == 0) {
316 switch(si.wProcessorArchitecture) {
317 case PROCESSOR_ARCHITECTURE_AMD64: arch = "amd64"; break;
318 case PROCESSOR_ARCHITECTURE_ARM: arch = "arm"; break;
319 case PROCESSOR_ARCHITECTURE_IA64: arch = "ia64"; break;
320 case PROCESSOR_ARCHITECTURE_INTEL: arch = "x86"; break;
321 default: arch = "unknown";
323 strncpy(buf->machine, arch, sizeof(buf->machine)-1);