initial load of upstream version 1.06.32
[xmlrpc-c] / lib / abyss / src / socket_win.c
1 /*=============================================================================\r
2                                  socket_win.c\r
3 ===============================================================================\r
4   This is the implementation of TSocket for a Windows Winsock socket.\r
5 =============================================================================*/\r
6 \r
7 #include "xmlrpc_config.h"\r
8 \r
9 #include <stdlib.h>\r
10 #include <stdio.h>\r
11 #include <string.h>\r
12 #include <assert.h>\r
13 #include <winsock.h>\r
14 \r
15 #include "xmlrpc-c/util_int.h"\r
16 #include "mallocvar.h"\r
17 #include "trace.h"\r
18 \r
19 #include "socket.h"\r
20 \r
21 \r
22 struct socketWin {\r
23 /*----------------------------------------------------------------------------\r
24    The properties/state of a TSocket unique to a Unix TSocket.\r
25 -----------------------------------------------------------------------------*/\r
26     SOCKET fd;\r
27     abyss_bool userSuppliedWinsock;\r
28         /* 'socket' was supplied by the user; it belongs to him */\r
29 };\r
30 \r
31 \r
32 \r
33 void\r
34 SocketWinInit(abyss_bool * const succeededP) {\r
35 \r
36     WORD wVersionRequested;\r
37     WSADATA wsaData;\r
38     int err;\r
39 \r
40     wVersionRequested = MAKEWORD(2, 0);\r
41 \r
42     err = WSAStartup(wVersionRequested, &wsaData);\r
43     *succeededP = (err == 0);\r
44 }\r
45 \r
46 \r
47 \r
48 void\r
49 SocketWinTerm(void) {\r
50 \r
51     WSACleanup();\r
52 }\r
53 \r
54 \r
55 \r
56 static SocketDestroyImpl            socketDestroy;\r
57 static SocketWriteImpl              socketWrite;\r
58 static SocketReadImpl               socketRead;\r
59 static SocketConnectImpl            socketConnect;\r
60 static SocketBindImpl               socketBind;\r
61 static SocketListenImpl             socketListen;\r
62 static SocketAcceptImpl             socketAccept;\r
63 static SocketErrorImpl              socketError;\r
64 static SocketWaitImpl               socketWait;\r
65 static SocketAvailableReadBytesImpl socketAvailableReadBytes;\r
66 static SocketGetPeerNameImpl        socketGetPeerName;\r
67 \r
68 \r
69 static struct TSocketVtbl const vtbl = {\r
70     &socketDestroy,\r
71     &socketWrite,\r
72     &socketRead,\r
73     &socketConnect,\r
74     &socketBind,\r
75     &socketListen,\r
76     &socketAccept,\r
77     &socketError,\r
78     &socketWait,\r
79     &socketAvailableReadBytes,\r
80     &socketGetPeerName\r
81 };\r
82 \r
83 \r
84 \r
85 void\r
86 SocketWinCreate(TSocket ** const socketPP) {\r
87 \r
88     struct socketWin * socketWinP;\r
89 \r
90     MALLOCVAR(socketWinP);\r
91 \r
92     if (socketWinP) {\r
93         SOCKET rc;\r
94         rc = socket(AF_INET, SOCK_STREAM, 0);\r
95         if (rc < 0)\r
96             *socketPP = NULL;\r
97         else {\r
98             socketWinP->fd = rc;\r
99             socketWinP->userSuppliedWinsock = FALSE;\r
100 \r
101             {\r
102                 int32_t n = 1;\r
103                 int rc;\r
104                 rc = setsockopt(socketWinP->fd, SOL_SOCKET, SO_REUSEADDR,\r
105                                 (char*)&n, sizeof(n));\r
106                 if (rc < 0)\r
107                     *socketPP = NULL;\r
108                 else\r
109                     SocketCreate(&vtbl, socketWinP, socketPP);\r
110             }\r
111             if (!*socketPP)\r
112                 closesocket(socketWinP->fd);\r
113         }\r
114         if (!*socketPP)\r
115             free(socketWinP);\r
116     } else\r
117         *socketPP = NULL;\r
118 }\r
119 \r
120 \r
121 \r
122 void\r
123 SocketWinCreateWinsock(SOCKET     const winsock,\r
124                        TSocket ** const socketPP) {\r
125 \r
126     struct socketWin * socketWinP;\r
127 \r
128     MALLOCVAR(socketWinP);\r
129 \r
130     if (socketWinP) {\r
131         socketWinP->fd = winsock;\r
132         socketWinP->userSuppliedWinsock = TRUE;\r
133 \r
134         SocketCreate(&vtbl, socketWinP, socketPP);\r
135 \r
136         if (!*socketPP)\r
137             free(socketWinP);\r
138     } else\r
139         *socketPP = NULL;\r
140 }\r
141 \r
142 \r
143 \r
144 void\r
145 socketDestroy(TSocket * const socketP) {\r
146 \r
147     struct socketWin * const socketWinP = socketP->implP;\r
148 \r
149     if (!socketWinP->userSuppliedWinsock)\r
150         closesocket(socketWinP->fd);\r
151 \r
152     free(socketWinP);\r
153 }\r
154 \r
155 \r
156 \r
157 void\r
158 socketWrite(TSocket *             const socketP,\r
159             const unsigned char * const buffer,\r
160             uint32_t              const len,\r
161             abyss_bool *          const failedP) {\r
162 \r
163     struct socketWin * const socketWinP = socketP->implP;\r
164 \r
165     size_t bytesLeft;\r
166     abyss_bool error;\r
167 \r
168     assert(sizeof(size_t) >= sizeof(len));\r
169 \r
170     for (bytesLeft = len, error = FALSE;\r
171          bytesLeft > 0 && !error;\r
172         ) {\r
173         size_t const maxSend = (size_t)(-1) >> 1;\r
174 \r
175         int rc;\r
176 \r
177         rc = send(socketWinP->fd, &buffer[len-bytesLeft],\r
178                   MIN(maxSend, bytesLeft), 0);\r
179 \r
180         if (rc <= 0)\r
181             /* 0 means connection closed; < 0 means severe error */\r
182             error = TRUE;\r
183         else\r
184             bytesLeft -= rc;\r
185     }\r
186     *failedP = error;\r
187 }\r
188 \r
189 \r
190 \r
191 uint32_t\r
192 socketRead(TSocket * const socketP,\r
193            char *    const buffer,\r
194            uint32_t  const len) {\r
195 \r
196     struct socketWin * const socketWinP = socketP->implP;\r
197 \r
198     int rc;\r
199     rc = recv(socketWinP->fd, buffer, len, 0);\r
200     return rc;\r
201 }\r
202 \r
203 \r
204 \r
205 abyss_bool\r
206 socketConnect(TSocket * const socketP,\r
207               TIPAddr * const addrP,\r
208               uint16_t  const portNumber) {\r
209 \r
210     struct socketWin * const socketWinP = socketP->implP;\r
211 \r
212     struct sockaddr_in name;\r
213     int rc;\r
214 \r
215     name.sin_family = AF_INET;\r
216     name.sin_port = htons(portNumber);\r
217     name.sin_addr = *addrP;\r
218 \r
219     rc = connect(socketWinP->fd, (struct sockaddr *)&name, sizeof(name));\r
220 \r
221     return rc != -1;\r
222 }\r
223 \r
224 \r
225 \r
226 abyss_bool\r
227 socketBind(TSocket * const socketP,\r
228            TIPAddr * const addrP,\r
229            uint16_t  const portNumber) {\r
230 \r
231     struct socketWin * const socketWinP = socketP->implP;\r
232 \r
233     struct sockaddr_in name;\r
234     int rc;\r
235 \r
236     name.sin_family = AF_INET;\r
237     name.sin_port   = htons(portNumber);\r
238     if (addrP)\r
239         name.sin_addr = *addrP;\r
240     else\r
241         name.sin_addr.s_addr = INADDR_ANY;\r
242 \r
243     rc = bind(socketWinP->fd, (struct sockaddr *)&name, sizeof(name));\r
244 \r
245     return (rc != -1);\r
246 }\r
247 \r
248 \r
249 \r
250 abyss_bool\r
251 socketListen(TSocket * const socketP,\r
252              uint32_t  const backlog) {\r
253 \r
254     struct socketWin * const socketWinP = socketP->implP;\r
255 \r
256     int32_t const minus1 = -1;\r
257 \r
258     int rc;\r
259 \r
260     /* Disable the Nagle algorithm to make persistant connections faster */\r
261 \r
262     setsockopt(socketWinP->fd, IPPROTO_TCP,TCP_NODELAY,\r
263                (const char *)&minus1, sizeof(minus1));\r
264 \r
265     rc = listen(socketWinP->fd, backlog);\r
266 \r
267     return (rc != -1);\r
268 }\r
269 \r
270 \r
271 \r
272 static void\r
273 socketAccept(TSocket *    const listenSocketP,\r
274              abyss_bool * const connectedP,\r
275              abyss_bool * const failedP,\r
276              TSocket **   const acceptedSocketPP,\r
277              TIPAddr *    const ipAddrP) {\r
278 /*----------------------------------------------------------------------------\r
279    Accept a connection on the listening socket 'listenSocketP'.  Return as\r
280    *acceptedSocketPP the socket for the accepted connection.\r
281 \r
282    If no connection is waiting on 'listenSocketP', wait until one is.\r
283 \r
284    If we receive a signal while waiting, return immediately.\r
285 \r
286    Return *connectedP true iff we accepted a connection.  Return\r
287    *failedP true iff we were unable to accept a connection for some\r
288    reason other than that we were interrupted.  Return both false if\r
289    our wait for a connection was interrupted by a signal.\r
290 -----------------------------------------------------------------------------*/\r
291     struct socketWin * const listenSocketWinP = listenSocketP->implP;\r
292 \r
293     abyss_bool connected, failed, interrupted;\r
294 \r
295     connected   = FALSE;\r
296     failed      = FALSE;\r
297     interrupted = FALSE;\r
298 \r
299     while (!connected && !failed && !interrupted) {\r
300         struct sockaddr_in sa;\r
301         socklen_t size = sizeof(sa);\r
302         int rc;\r
303         rc = accept(listenSocketWinP->fd, (struct sockaddr *)&sa, &size);\r
304         if (rc >= 0) {\r
305             SOCKET const acceptedWinsock = rc;\r
306             struct socketWin * acceptedSocketWinP;\r
307 \r
308             MALLOCVAR(acceptedSocketWinP);\r
309 \r
310             if (acceptedSocketWinP) {\r
311                 acceptedSocketWinP->fd = acceptedWinsock;\r
312                 acceptedSocketWinP->userSuppliedWinsock = FALSE;\r
313 \r
314                 SocketCreate(&vtbl, acceptedSocketWinP, acceptedSocketPP);\r
315                 if (!*acceptedSocketPP)\r
316                     failed = TRUE;\r
317                 else {\r
318                     connected = TRUE;\r
319                     *ipAddrP = sa.sin_addr;\r
320                 }\r
321                 if (failed)\r
322                     free(acceptedSocketWinP);\r
323             } else\r
324                 failed = TRUE;\r
325             if (failed)\r
326                 closesocket(acceptedWinsock);\r
327         } else if (socketError(NULL) == WSAEINTR)\r
328             interrupted = TRUE;\r
329         else\r
330             failed = TRUE;\r
331     }\r
332     *failedP    = failed;\r
333     *connectedP = connected;\r
334 }\r
335 \r
336 \r
337 \r
338 static uint32_t\r
339 socketWait(TSocket *  const socketP,\r
340            abyss_bool const rd,\r
341            abyss_bool const wr,\r
342            uint32_t   const timems) {\r
343 \r
344     struct socketWin * const socketWinP = socketP->implP;\r
345 \r
346     fd_set rfds, wfds;\r
347     TIMEVAL tv;\r
348 \r
349     FD_ZERO(&rfds);\r
350     FD_ZERO(&wfds);\r
351 \r
352     if (rd)\r
353         FD_SET(socketWinP->fd, &rfds);\r
354 \r
355     if (wr)\r
356         FD_SET(socketWinP->fd, &wfds);\r
357 \r
358     tv.tv_sec  = timems / 1000;\r
359     tv.tv_usec = timems % 1000;\r
360 \r
361     for (;;) {\r
362         int rc;\r
363 \r
364         rc = select(socketWinP->fd + 1, &rfds, &wfds, NULL,\r
365                     (timems == TIME_INFINITE ? NULL : &tv));\r
366 \r
367         switch(rc) {\r
368         case 0: /* time out */\r
369             return 0;\r
370 \r
371         case -1:  /* socket error */\r
372             if (socketError(NULL) == WSAEINTR)\r
373                 break;\r
374 \r
375             return 0;\r
376 \r
377         default:\r
378             if (FD_ISSET(socketWinP->fd, &rfds))\r
379                 return 1;\r
380             if (FD_ISSET(socketWinP->fd, &wfds))\r
381                 return 2;\r
382             return 0;\r
383         }\r
384     }\r
385 }\r
386 \r
387 \r
388 \r
389 static uint32_t\r
390 socketAvailableReadBytes(TSocket * const socketP) {\r
391 \r
392     struct socketWin * const socketWinP = socketP->implP;\r
393 \r
394     uint32_t x;\r
395     int rc;\r
396 \r
397     rc = ioctlsocket(socketWinP->fd, FIONREAD, &x);\r
398 \r
399     return rc == 0 ? x : 0;\r
400 }\r
401 \r
402 \r
403 \r
404 static void\r
405 socketGetPeerName(TSocket *    const socketP,\r
406                   TIPAddr *    const ipAddrP,\r
407                   uint16_t *   const portNumberP,\r
408                   abyss_bool * const successP) {\r
409 \r
410     struct socketWin * const socketWinP = socketP->implP;\r
411 \r
412     socklen_t addrlen;\r
413     int rc;\r
414     struct sockaddr sockAddr;\r
415 \r
416     addrlen = sizeof(sockAddr);\r
417 \r
418     rc = getpeername(socketWinP->fd, &sockAddr, &addrlen);\r
419 \r
420     if (rc < 0) {\r
421         TraceMsg("getpeername() failed.  errno=%d (%s)",\r
422                  errno, strerror(errno));\r
423         *successP = FALSE;\r
424     } else {\r
425         if (addrlen != sizeof(sockAddr)) {\r
426             TraceMsg("getpeername() returned a socket address of the wrong "\r
427                      "size: %u.  Expected %u", addrlen, sizeof(sockAddr));\r
428             *successP = FALSE;\r
429         } else {\r
430             if (sockAddr.sa_family != AF_INET) {\r
431                 TraceMsg("Socket does not use the Inet (IP) address "\r
432                          "family.  Instead it uses family %d",\r
433                          sockAddr.sa_family);\r
434                 *successP = FALSE;\r
435             } else {\r
436                 struct sockaddr_in * const sockAddrInP = (struct sockaddr_in *)\r
437                     &sockAddr;\r
438 \r
439                 *ipAddrP     = sockAddrInP->sin_addr;\r
440                 *portNumberP = sockAddrInP->sin_port;\r
441 \r
442                 *successP = TRUE;\r
443             }\r
444         }\r
445     }\r
446 }\r
447 \r
448 \r
449 \r
450 static uint32_t\r
451 socketError(TSocket * const socketP) {\r
452     return (uint32_t)WSAGetLastError();\r
453 }\r
454 \r
455 \r
456 \r