windows: Provide a cancellable usleep(), but with ms resolution only
[strongswan.git] / src / libstrongswan / utils / windows.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "utils.h"
17
18 #include <errno.h>
19
20 /**
21 * See header
22 */
23 void windows_init()
24 {
25 WSADATA wsad;
26
27 /* initialize winsock2 */
28 WSAStartup(MAKEWORD(2, 2), &wsad);
29 }
30
31 /**
32 * See header
33 */
34 void windows_deinit()
35 {
36 WSACleanup();
37 }
38
39 /**
40 * See header
41 */
42 int usleep(useconds_t usec)
43 {
44 if (usec > 0 && usec < 1000)
45 { /* do not Sleep(0) for small values */
46 usec = 1000;
47 }
48 SleepEx(usec / 1000, TRUE);
49 return 0;
50 }
51
52 /**
53 * See header
54 */
55 int socketpair(int domain, int type, int protocol, int sv[2])
56 {
57 struct sockaddr_in addr = {
58 .sin_family = AF_INET,
59 .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
60 };
61 socklen_t len = sizeof(addr);
62 int s, c, sc;
63 BOOL on;
64
65 /* We don't check domain for AF_INET, as we use it as replacement for
66 * AF_UNIX. */
67 if (type != SOCK_STREAM)
68 {
69 errno = EINVAL;
70 return -1;
71 }
72 if (protocol != 0 && protocol != IPPROTO_TCP)
73 {
74 errno = EINVAL;
75 return -1;
76 }
77 s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
78 if (s == -1)
79 {
80 return -1;
81 }
82 c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
83 if (c == -1)
84 {
85 closesocket(c);
86 return -1;
87 }
88 if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) == 0 &&
89 getsockname(s,(struct sockaddr*)&addr, &len) == 0 &&
90 listen(s, 0) == 0 &&
91 connect(c, (struct sockaddr*)&addr, sizeof(addr)) == 0)
92 {
93 sc = accept(s, NULL, NULL);
94 if (sc > 0)
95 {
96 closesocket(s);
97 s = sc;
98 if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
99 (void*)&on, sizeof(on)) == 0 &&
100 setsockopt(c, IPPROTO_TCP, TCP_NODELAY,
101 (void*)&on, sizeof(on)) == 0)
102 {
103 sv[0] = s;
104 sv[1] = c;
105 return 0;
106 }
107 }
108 }
109 closesocket(s);
110 closesocket(c);
111 return -1;
112 }
113
114 /**
115 * Set errno for a function setting WSA error on failure
116 */
117 static int wserr(int retval)
118 {
119 if (retval < 0)
120 {
121 switch (WSAGetLastError())
122 {
123 case WSANOTINITIALISED:
124 errno = EBADF;
125 break;
126 case WSAENETDOWN:
127 case WSAENETRESET:
128 case WSAESHUTDOWN:
129 errno = EPIPE;
130 break;
131 case WSAEACCES:
132 errno = EACCES;
133 break;
134 case WSAEINTR:
135 errno = EINTR;
136 break;
137 case WSAEINPROGRESS:
138 errno = EBUSY;
139 break;
140 case WSAEFAULT:
141 errno = EFAULT;
142 break;
143 case WSAENOBUFS:
144 errno = ENOMEM;
145 break;
146 case WSAENOTSOCK:
147 errno = EINVAL;
148 break;
149 case WSAEOPNOTSUPP:
150 errno = ENOSYS;
151 break;
152 case WSAEWOULDBLOCK:
153 errno = EWOULDBLOCK;
154 break;
155 case WSAEMSGSIZE:
156 errno = ENOSPC;
157 break;
158 case WSAEINVAL:
159 errno = EINVAL;
160 break;
161 case WSAENOTCONN:
162 case WSAEHOSTUNREACH:
163 case WSAECONNABORTED:
164 case WSAECONNRESET:
165 errno = EIO;
166 break;
167 case WSAETIMEDOUT:
168 errno = ESRCH;
169 break;
170 default:
171 errno = ENOENT;
172 break;
173 }
174 }
175 else
176 {
177 errno = 0;
178 }
179 return retval;
180 }
181
182 /**
183 * Check and clear the dontwait flag
184 */
185 static bool check_dontwait(int *flags)
186 {
187 if (*flags & MSG_DONTWAIT)
188 {
189 *flags &= ~MSG_DONTWAIT;
190 return TRUE;
191 }
192 return FALSE;
193 }
194
195 /**
196 * See header
197 */
198 #undef recv
199 ssize_t windows_recv(int sockfd, void *buf, size_t len, int flags)
200 {
201 u_long on = 1, off = 0;
202 ssize_t outlen = -1;
203
204 if (!check_dontwait(&flags))
205 {
206 return wserr(recv(sockfd, buf, len, flags));
207 }
208 if (wserr(ioctlsocket(sockfd, FIONBIO, &on) == 0))
209 {
210 outlen = wserr(recv(sockfd, buf, len, flags));
211 ioctlsocket(sockfd, FIONBIO, &off);
212 }
213 return outlen;
214 }
215
216 /**
217 * See header
218 */
219 #undef recvfrom
220 ssize_t windows_recvfrom(int sockfd, void *buf, size_t len, int flags,
221 struct sockaddr *src_addr, socklen_t *addrlen)
222 {
223 u_long on = 1, off = 0;
224 ssize_t outlen = -1;
225
226 if (!check_dontwait(&flags))
227 {
228 return wserr(recvfrom(sockfd, buf, len, flags, src_addr, addrlen));
229 }
230 if (wserr(ioctlsocket(sockfd, FIONBIO, &on)) == 0)
231 {
232 outlen = wserr(recvfrom(sockfd, buf, len, flags, src_addr, addrlen));
233 ioctlsocket(sockfd, FIONBIO, &off);
234 }
235 return outlen;
236 }
237
238 /**
239 * See header
240 */
241 #undef send
242 ssize_t windows_send(int sockfd, const void *buf, size_t len, int flags)
243 {
244 u_long on = 1, off = 0;
245 ssize_t outlen = -1;
246
247 if (!check_dontwait(&flags))
248 {
249 return wserr(send(sockfd, buf, len, flags));
250 }
251 if (wserr(ioctlsocket(sockfd, FIONBIO, &on)) == 0)
252 {
253 outlen = wserr(send(sockfd, buf, len, flags));
254 ioctlsocket(sockfd, FIONBIO, &off);
255 }
256 return outlen;
257 }
258
259 /**
260 * See header
261 */
262 #undef sendto
263 ssize_t windows_sendto(int sockfd, const void *buf, size_t len, int flags,
264 const struct sockaddr *dest_addr, socklen_t addrlen)
265 {
266 u_long on = 1, off = 0;
267 ssize_t outlen = -1;
268
269 if (!check_dontwait(&flags))
270 {
271 return wserr(sendto(sockfd, buf, len, flags, dest_addr, addrlen));
272 }
273 if (wserr(ioctlsocket(sockfd, FIONBIO, &on)) == 0)
274 {
275 outlen = wserr(sendto(sockfd, buf, len, flags, dest_addr, addrlen));
276 ioctlsocket(sockfd, FIONBIO, &off);
277 }
278 return outlen;
279 }