1 /*=============================================================================
\r
3 ===============================================================================
\r
4 This is the implementation of TSocket for a Windows Winsock socket.
\r
5 =============================================================================*/
\r
7 #include "xmlrpc_config.h"
\r
13 #include <winsock.h>
\r
15 #include "xmlrpc-c/util_int.h"
\r
16 #include "mallocvar.h"
\r
23 /*----------------------------------------------------------------------------
\r
24 The properties/state of a TSocket unique to a Unix TSocket.
\r
25 -----------------------------------------------------------------------------*/
\r
27 abyss_bool userSuppliedWinsock;
\r
28 /* 'socket' was supplied by the user; it belongs to him */
\r
34 SocketWinInit(abyss_bool * const succeededP) {
\r
36 WORD wVersionRequested;
\r
40 wVersionRequested = MAKEWORD(2, 0);
\r
42 err = WSAStartup(wVersionRequested, &wsaData);
\r
43 *succeededP = (err == 0);
\r
49 SocketWinTerm(void) {
\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
69 static struct TSocketVtbl const vtbl = {
\r
79 &socketAvailableReadBytes,
\r
86 SocketWinCreate(TSocket ** const socketPP) {
\r
88 struct socketWin * socketWinP;
\r
90 MALLOCVAR(socketWinP);
\r
94 rc = socket(AF_INET, SOCK_STREAM, 0);
\r
98 socketWinP->fd = rc;
\r
99 socketWinP->userSuppliedWinsock = FALSE;
\r
104 rc = setsockopt(socketWinP->fd, SOL_SOCKET, SO_REUSEADDR,
\r
105 (char*)&n, sizeof(n));
\r
109 SocketCreate(&vtbl, socketWinP, socketPP);
\r
112 closesocket(socketWinP->fd);
\r
123 SocketWinCreateWinsock(SOCKET const winsock,
\r
124 TSocket ** const socketPP) {
\r
126 struct socketWin * socketWinP;
\r
128 MALLOCVAR(socketWinP);
\r
131 socketWinP->fd = winsock;
\r
132 socketWinP->userSuppliedWinsock = TRUE;
\r
134 SocketCreate(&vtbl, socketWinP, socketPP);
\r
145 socketDestroy(TSocket * const socketP) {
\r
147 struct socketWin * const socketWinP = socketP->implP;
\r
149 if (!socketWinP->userSuppliedWinsock)
\r
150 closesocket(socketWinP->fd);
\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
163 struct socketWin * const socketWinP = socketP->implP;
\r
168 assert(sizeof(size_t) >= sizeof(len));
\r
170 for (bytesLeft = len, error = FALSE;
\r
171 bytesLeft > 0 && !error;
\r
173 size_t const maxSend = (size_t)(-1) >> 1;
\r
177 rc = send(socketWinP->fd, &buffer[len-bytesLeft],
\r
178 MIN(maxSend, bytesLeft), 0);
\r
181 /* 0 means connection closed; < 0 means severe error */
\r
192 socketRead(TSocket * const socketP,
\r
193 char * const buffer,
\r
194 uint32_t const len) {
\r
196 struct socketWin * const socketWinP = socketP->implP;
\r
199 rc = recv(socketWinP->fd, buffer, len, 0);
\r
206 socketConnect(TSocket * const socketP,
\r
207 TIPAddr * const addrP,
\r
208 uint16_t const portNumber) {
\r
210 struct socketWin * const socketWinP = socketP->implP;
\r
212 struct sockaddr_in name;
\r
215 name.sin_family = AF_INET;
\r
216 name.sin_port = htons(portNumber);
\r
217 name.sin_addr = *addrP;
\r
219 rc = connect(socketWinP->fd, (struct sockaddr *)&name, sizeof(name));
\r
227 socketBind(TSocket * const socketP,
\r
228 TIPAddr * const addrP,
\r
229 uint16_t const portNumber) {
\r
231 struct socketWin * const socketWinP = socketP->implP;
\r
233 struct sockaddr_in name;
\r
236 name.sin_family = AF_INET;
\r
237 name.sin_port = htons(portNumber);
\r
239 name.sin_addr = *addrP;
\r
241 name.sin_addr.s_addr = INADDR_ANY;
\r
243 rc = bind(socketWinP->fd, (struct sockaddr *)&name, sizeof(name));
\r
251 socketListen(TSocket * const socketP,
\r
252 uint32_t const backlog) {
\r
254 struct socketWin * const socketWinP = socketP->implP;
\r
256 int32_t const minus1 = -1;
\r
260 /* Disable the Nagle algorithm to make persistant connections faster */
\r
262 setsockopt(socketWinP->fd, IPPROTO_TCP,TCP_NODELAY,
\r
263 (const char *)&minus1, sizeof(minus1));
\r
265 rc = listen(socketWinP->fd, backlog);
\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
282 If no connection is waiting on 'listenSocketP', wait until one is.
\r
284 If we receive a signal while waiting, return immediately.
\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
293 abyss_bool connected, failed, interrupted;
\r
297 interrupted = FALSE;
\r
299 while (!connected && !failed && !interrupted) {
\r
300 struct sockaddr_in sa;
\r
301 socklen_t size = sizeof(sa);
\r
303 rc = accept(listenSocketWinP->fd, (struct sockaddr *)&sa, &size);
\r
305 SOCKET const acceptedWinsock = rc;
\r
306 struct socketWin * acceptedSocketWinP;
\r
308 MALLOCVAR(acceptedSocketWinP);
\r
310 if (acceptedSocketWinP) {
\r
311 acceptedSocketWinP->fd = acceptedWinsock;
\r
312 acceptedSocketWinP->userSuppliedWinsock = FALSE;
\r
314 SocketCreate(&vtbl, acceptedSocketWinP, acceptedSocketPP);
\r
315 if (!*acceptedSocketPP)
\r
319 *ipAddrP = sa.sin_addr;
\r
322 free(acceptedSocketWinP);
\r
326 closesocket(acceptedWinsock);
\r
327 } else if (socketError(NULL) == WSAEINTR)
\r
328 interrupted = TRUE;
\r
333 *connectedP = connected;
\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
344 struct socketWin * const socketWinP = socketP->implP;
\r
353 FD_SET(socketWinP->fd, &rfds);
\r
356 FD_SET(socketWinP->fd, &wfds);
\r
358 tv.tv_sec = timems / 1000;
\r
359 tv.tv_usec = timems % 1000;
\r
364 rc = select(socketWinP->fd + 1, &rfds, &wfds, NULL,
\r
365 (timems == TIME_INFINITE ? NULL : &tv));
\r
368 case 0: /* time out */
\r
371 case -1: /* socket error */
\r
372 if (socketError(NULL) == WSAEINTR)
\r
378 if (FD_ISSET(socketWinP->fd, &rfds))
\r
380 if (FD_ISSET(socketWinP->fd, &wfds))
\r
390 socketAvailableReadBytes(TSocket * const socketP) {
\r
392 struct socketWin * const socketWinP = socketP->implP;
\r
397 rc = ioctlsocket(socketWinP->fd, FIONREAD, &x);
\r
399 return rc == 0 ? x : 0;
\r
405 socketGetPeerName(TSocket * const socketP,
\r
406 TIPAddr * const ipAddrP,
\r
407 uint16_t * const portNumberP,
\r
408 abyss_bool * const successP) {
\r
410 struct socketWin * const socketWinP = socketP->implP;
\r
414 struct sockaddr sockAddr;
\r
416 addrlen = sizeof(sockAddr);
\r
418 rc = getpeername(socketWinP->fd, &sockAddr, &addrlen);
\r
421 TraceMsg("getpeername() failed. errno=%d (%s)",
\r
422 errno, strerror(errno));
\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
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
436 struct sockaddr_in * const sockAddrInP = (struct sockaddr_in *)
\r
439 *ipAddrP = sockAddrInP->sin_addr;
\r
440 *portNumberP = sockAddrInP->sin_port;
\r
451 socketError(TSocket * const socketP) {
\r
452 return (uint32_t)WSAGetLastError();
\r