static void chanSwitchListen(TChanSwitch * const chanSwitchP, uint32_t const backlog, const char ** const errorP) { struct socketWin * const socketWinP = chanSwitchP->implP; int32_t const minus1 = -1; int rc; /* Disable the Nagle algorithm to make persistant connections faster */ setsockopt(socketWinP->winsock, IPPROTO_TCP, TCP_NODELAY, (const char *)&minus1, sizeof(minus1)); rc = listen(socketWinP->winsock, backlog); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "setsockopt() failed with WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else *errorP = NULL; }
void bindSocketToPort(SOCKET const winsock, struct in_addr * const addrP, uint16_t const portNumber, const char ** const errorP) { struct sockaddr_in name; int rc; int one = 1; ZeroMemory(&name, sizeof(name)); name.sin_family = AF_INET; name.sin_port = htons(portNumber); if (addrP) name.sin_addr = *addrP; setsockopt(winsock, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)); rc = bind(winsock, (struct sockaddr *)&name, sizeof(name)); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "Unable to bind socket to port number %u. " "bind() failed with WSAERROR %i (%s)", portNumber, lastError, getWSAError(lastError)); } else *errorP = NULL; }
static void channelRead(TChannel * const channelP, unsigned char * const buffer, uint32_t const bufferSize, uint32_t * const bytesReceivedP, bool * const failedP) { struct socketWin * const socketWinP = channelP->implP; int retries = 300; for (*failedP = TRUE; *failedP && retries; retries--) { int rc = recv(socketWinP->winsock, buffer, bufferSize, 0); int lastError = WSAGetLastError(); if (rc < 0) { if (lastError == WSAEWOULDBLOCK || lastError == ERROR_IO_PENDING) { fprintf(stderr, "Abyss: recv() failed with errno %d (%s) cnt %d, will retry\n", lastError, getWSAError(lastError), retries); SleepEx(30, TRUE); /* give socket another chance after xx millisec)*/ *failedP = FALSE; } else { fprintf(stderr, "Abyss: recv() failed with errno %d (%s)\n", lastError, getWSAError(lastError)); break; } } else { *failedP = FALSE; *bytesReceivedP = rc; if (ChannelTraceIsActive) fprintf(stderr, "Abyss channel: read %u bytes: '%.*s'\n", bytesReceivedP, (int)(*bytesReceivedP), buffer); } } }
static void chanSwitchAccept(TChanSwitch * const chanSwitchP, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Accept a connection via the channel switch *chanSwitchP. Return as *channelPP the channel for the accepted connection. If no connection is waiting at *chanSwitchP, wait until one is. If we receive a signal while waiting, return immediately with *channelPP == NULL. -----------------------------------------------------------------------------*/ struct socketWin * const listenSocketP = chanSwitchP->implP; bool interrupted; TChannel * channelP; interrupted = FALSE; /* Haven't been interrupted yet */ channelP = NULL; /* No connection yet */ *errorP = NULL; /* No error yet */ while (!channelP && !*errorP && !interrupted) { struct sockaddr peerAddr; socklen_t size = sizeof(peerAddr); int rc; rc = accept(listenSocketP->winsock, &peerAddr, &size); if (rc >= 0) { int const acceptedWinsock = rc; createChannelForAccept(acceptedWinsock, peerAddr, &channelP, channelInfoPP, errorP); if (*errorP) closesocket(acceptedWinsock); } else { int const lastError = WSAGetLastError(); if (lastError == WSAEINTR) interrupted = TRUE; else xmlrpc_asprintf(errorP, "accept() failed, WSA error = %d (%s)", lastError, getWSAError(lastError)); } } *channelPP = channelP; }
void ChannelWinCreateWinsock(SOCKET const fd, TChannel ** const channelPP, struct abyss_win_chaninfo ** const channelInfoPP, const char ** const errorP) { struct sockaddr peerAddr; socklen_t peerAddrLen; int rc; peerAddrLen = sizeof(peerAddr); rc = getpeername(fd, &peerAddr, &peerAddrLen); if (rc != 0) { int const lastError = WSAGetLastError(); if (lastError == WSAENOTCONN) { /* NOTE: This specific string 'not in connected' is required by one of the rpctest suite items, in abyss.c (line 186), hence the separation of the error messages in this case ... */ xmlrpc_asprintf(errorP, "Socket on file descriptor %d " "is not in connected state. WSAERROR = %d (%s)", fd, lastError, getWSAError(lastError)); } else xmlrpc_asprintf(errorP, "getpeername() failed. WSAERROR = %d (%s)", lastError, getWSAError(lastError)); } else { makeChannelInfo(channelInfoPP, peerAddr, peerAddrLen, errorP); if (!*errorP) { makeChannelFromWinsock(fd, channelPP, errorP); if (*errorP) free(*channelInfoPP); } } }
void ChanSwitchWinCreate(uint16_t const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Create a Winsock-based channel switch. Set the socket's local address so that a subsequent "listen" will listen on all IP addresses, port number 'portNumber'. -----------------------------------------------------------------------------*/ struct socketWin * socketWinP; MALLOCVAR(socketWinP); if (!socketWinP) xmlrpc_asprintf(errorP, "Unable to allocate memory for Windows socket " "descriptor structure."); else { SOCKET winsock; winsock = socket(AF_INET, SOCK_STREAM, 0); if (winsock == 0 || winsock == INVALID_SOCKET) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "socket() failed with WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else { socketWinP->winsock = winsock; socketWinP->userSuppliedWinsock = FALSE; socketWinP->interruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL); setSocketOptions(socketWinP->winsock, errorP); if (!*errorP) { bindSocketToPort(socketWinP->winsock, NULL, portNumber, errorP); if (!*errorP) ChanSwitchCreate(&chanSwitchVtbl, socketWinP, chanSwitchPP); } if (*errorP) { CloseHandle(socketWinP->interruptEvent); closesocket(winsock); } } if (*errorP) free(socketWinP); } }
void ChanSwitchWinCreate2(int const protocolFamily, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { struct socketWin * socketWinP; MALLOCVAR(socketWinP); if (!socketWinP) xmlrpc_asprintf(errorP, "Unable to allocate memory for Windows socket " "descriptor structure."); else { SOCKET winsock; winsock = socket(protocolFamily, SOCK_STREAM, 0); if (winsock == 0 || winsock == INVALID_SOCKET) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "socket() failed with WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else { socketWinP->winsock = winsock; socketWinP->userSuppliedWinsock = FALSE; socketWinP->interruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL); setSocketOptions(socketWinP->winsock, errorP); if (!*errorP) { bindSocketToAddr(socketWinP->winsock, sockAddrP, sockAddrLen, errorP); if (!*errorP) ChanSwitchCreate(&chanSwitchVtbl, socketWinP, chanSwitchPP); } if (*errorP) { CloseHandle(socketWinP->interruptEvent); closesocket(winsock); } } if (*errorP) free(socketWinP); } }
static void setSocketOptions(SOCKET const fd, const char ** const errorP) { int32_t const n = 1; int rc; rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof(n)); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "Failed to set socket options. " "setsockopt() failed with WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else *errorP = NULL; }
void SocketWinInit(const char ** const errorP) { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 0); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "WSAStartup() faild with error %d (%s)", lastError, getWSAError(lastError)); } else *errorP = NULL; }
static void bindSocketToAddr(SOCKET const winsock, const struct sockaddr * const addrP, socklen_t const sockAddrLen, const char ** const errorP) { int rc; rc = bind(winsock, (struct sockaddr *)addrP, sockAddrLen); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "Unable to bind socket to the socket address. " "bind() failed with WSAERROR %i (%s)", lastError, getWSAError(lastError)); } else *errorP = NULL; }
static void channelFormatPeerInfo(TChannel * const channelP, const char ** const peerStringP) { struct socketWin * const socketWinP = channelP->implP; struct sockaddr sockaddr; socklen_t sockaddrLen; int rc; sockaddrLen = sizeof(sockaddr); rc = getpeername(socketWinP->winsock, &sockaddr, &sockaddrLen); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(peerStringP, "?? getpeername() failed. " "WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else { switch (sockaddr.sa_family) { case AF_INET: { struct sockaddr_in * const sockaddrInP = (struct sockaddr_in *) &sockaddr; if (sockaddrLen < sizeof(*sockaddrInP)) xmlrpc_asprintf(peerStringP, "??? getpeername() returned " "the wrong size"); else { unsigned char * const ipaddr = (unsigned char *) &sockaddrInP->sin_addr.s_addr; xmlrpc_asprintf(peerStringP, "%u.%u.%u.%u:%hu", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3], sockaddrInP->sin_port); } } break; default: xmlrpc_asprintf(peerStringP, "??? AF=%u", sockaddr.sa_family); } } }
void ChannelWinGetPeerName(TChannel * const channelP, struct sockaddr_in * const inAddrP, const char ** const errorP) { struct socketWin * const socketWinP = channelP->implP; socklen_t addrlen; int rc; struct sockaddr sockAddr; addrlen = sizeof(sockAddr); rc = getpeername(socketWinP->winsock, &sockAddr, &addrlen); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "getpeername() failed. WSA error = %d (%s)", lastError, getWSAError(lastError)); } else { if (addrlen != sizeof(sockAddr)) xmlrpc_asprintf(errorP, "getpeername() returned a socket address " "of the wrong size: %u. Expected %u", addrlen, sizeof(sockAddr)); else { if (sockAddr.sa_family != AF_INET) xmlrpc_asprintf(errorP, "Socket does not use the Inet (IP) address " "family. Instead it uses family %d", sockAddr.sa_family); else { *inAddrP = *(struct sockaddr_in *)&sockAddr; *errorP = NULL; } } } }
static void chanSwitchAccept(TChanSwitch * const chanSwitchP, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Accept a connection via the channel switch *chanSwitchP. Return as *channelPP the channel for the accepted connection. If no connection is waiting at *chanSwitchP, wait until one is. If we receive a signal while waiting, return immediately with *channelPP == NULL. -----------------------------------------------------------------------------*/ struct socketWin * const listenSocketP = chanSwitchP->implP; HANDLE acceptEvent = WSACreateEvent(); bool interrupted; TChannel * channelP; interrupted = FALSE; /* Haven't been interrupted yet */ channelP = NULL; /* No connection yet */ *errorP = NULL; /* No error yet */ WSAEventSelect(listenSocketP->winsock, acceptEvent, FD_ACCEPT | FD_CLOSE | FD_READ); while (!channelP && !*errorP && !interrupted) { HANDLE interrupts[2] = {acceptEvent, listenSocketP->interruptEvent}; int rc; struct sockaddr peerAddr; socklen_t size = sizeof(peerAddr); rc = WaitForMultipleObjects(2, interrupts, FALSE, INFINITE); if (WAIT_OBJECT_0 + 1 == rc) { interrupted = TRUE; continue; }; rc = accept(listenSocketP->winsock, &peerAddr, &size); if (rc >= 0) { int const acceptedWinsock = rc; createChannelForAccept(acceptedWinsock, peerAddr, &channelP, channelInfoPP, errorP); if (*errorP) closesocket(acceptedWinsock); } else { int const lastError = WSAGetLastError(); if (lastError == WSAEINTR) interrupted = TRUE; else xmlrpc_asprintf(errorP, "accept() failed, WSA error = %d (%s)", lastError, getWSAError(lastError)); } } *channelPP = channelP; CloseHandle(acceptEvent); }
static void channelWrite(TChannel * const channelP, const unsigned char * const buffer, uint32_t const len, bool * const failedP) { struct socketWin * const socketWinP = channelP->implP; size_t bytesLeft; bool error; int to_count = 0; int lastError = 0; for (bytesLeft = len, error = FALSE; bytesLeft > 0 && !error;) { size_t const maxSend = 4096 * 2; /* with respect to resource allocation this might be a better value than 2^31 */ int rc = send(socketWinP->winsock, buffer + len - bytesLeft, MIN(maxSend, bytesLeft), 0); if (rc > 0) { /* 0 means connection closed; < 0 means severe error */ to_count = 0; bytesLeft -= rc; } else if (!rc) { error = TRUE; fprintf(stderr, "Abyss: send() failed: connection closed"); } else { error = TRUE; lastError = WSAGetLastError(); if (lastError == WSAEWOULDBLOCK || lastError == ERROR_IO_PENDING) { SleepEx(20, TRUE); /* give socket another chance after xx millisec) */ if (++to_count < 300) { error = FALSE; } // fprintf(stderr, "Abyss: send() failed with errno %d (%s) cnt %d, will retry\n", lastError, getWSAError(lastError), to_count); } if (error) fprintf(stderr, "Abyss: send() failed with errno %d (%s)\n", lastError, getWSAError(lastError)); } } *failedP = error; }