int haveMessage( PAPIConnection * inConnection ) { int bHaveMessage = 0; int theRC; theRC = socketPoll( inConnection->mFD, inConnection->mFDPollTimeout ); if ( theRC == 1 ) { char theByte; if ( recv( inConnection->mFD, &theByte, 1, MSG_PEEK ) != 1 ) { if ( errno != EINTR ) { bHaveMessage = -1; } } else { bHaveMessage = 1; } } else { bHaveMessage = -1; } return bHaveMessage; }
void dhcpv6RelayTask(void *param) { error_t error; uint_t i; //Point to the DHCPv6 relay agent context Dhcpv6RelayCtx *context = (Dhcpv6RelayCtx *) param; //Specify the events the application is interested in for //each client-facing sockets for(i = 0; i < context->clientInterfaceCount; i++) { context->eventDesc[i].socket = context->clientSocket[i]; context->eventDesc[i].eventMask = SOCKET_EVENT_RX_READY; } //Specify the events the application is interested in for //the network-facing socket context->eventDesc[i].socket = context->serverSocket; context->eventDesc[i].eventMask = SOCKET_EVENT_RX_READY; //Main loop while(1) { //Wait for incoming packets on network-facing or client-facing interfaces error = socketPoll(context->eventDesc, context->clientInterfaceCount + 1, context->event, INFINITE_DELAY); //Stop DHCPv6 relay agent? if(context->stopRequest) { //The DHCPv6 relay agent is about to stop context->stopRequest = FALSE; context->running = FALSE; //Acknowledge the reception of the user request osEventSet(context->ackEvent); //Kill ourselves osTaskDelete(NULL); } //Verify status code if(!error) { //Check the state of each client-facing socket for(i = 0; i < context->clientInterfaceCount; i++) { //Relay client messages if applicable if(context->eventDesc[i].eventFlags & SOCKET_EVENT_RX_READY) dhcpv6ForwardClientMessage(context, i); } //Check the state of the network-facing socket if(context->eventDesc[i].eventFlags & SOCKET_EVENT_RX_READY) { //Forward Relay-Reply messages from the network dhcpv6ForwardRelayReplyMessage(context); } } } }
void tcpEchoConnectionTask(void *param) { error_t error; uint_t n; uint_t writeIndex; uint_t readIndex; uint_t bufferLength; uint_t rxByteCount; uint_t txByteCount; time_t startTime; time_t duration; SocketEventDesc eventDesc; EchoServiceContext *context; //Get a pointer to the context context = (EchoServiceContext *) param; //Get current time startTime = osGetTickCount(); //Initialize variables writeIndex = 0; readIndex = 0; bufferLength = 0; rxByteCount = 0; txByteCount = 0; //Main loop while(1) { //Buffer is empty? if(!bufferLength) { //Get notified when the socket is readable eventDesc.socket = context->socket; eventDesc.eventMask = SOCKET_EVENT_RX_READY; } //Buffer is not empty of full? else if(bufferLength < ECHO_BUFFER_SIZE) { //Get notified when the socket is readable or writable eventDesc.socket = context->socket; eventDesc.eventMask = SOCKET_EVENT_RX_READY | SOCKET_EVENT_TX_READY; } //Buffer is full? else { //Get notified when the socket is writable eventDesc.socket = context->socket; eventDesc.eventMask = SOCKET_EVENT_TX_READY; } //Wait for an event to be fired error = socketPoll(&eventDesc, 1, NULL, ECHO_TIMEOUT); //Timeout error or any other exception to report? if(error) break; //The socket is available for reading if(eventDesc.eventFlags & SOCKET_EVENT_RX_READY) { //Read as much data as possible n = min(ECHO_BUFFER_SIZE - writeIndex, ECHO_BUFFER_SIZE - bufferLength); //Read incoming data error = socketReceive(context->socket, context->buffer + writeIndex, n, &n, 0); //Any error to report? if(error) break; //Increment write index writeIndex += n; //Wrap around if necessary if(writeIndex >= ECHO_BUFFER_SIZE) writeIndex = 0; //Increment buffer length bufferLength += n; //Total number of bytes received rxByteCount += n; } //The socket is available for writing? if(eventDesc.eventFlags & SOCKET_EVENT_TX_READY) { //Write as much data as possible n = min(ECHO_BUFFER_SIZE - readIndex, bufferLength); //Send data back to the client error = socketSend(context->socket, context->buffer + readIndex, n, &n, 0); //Any error to report? if(error && error != ERROR_TIMEOUT) break; //Increment read index readIndex += n; //Wrap around if necessary if(readIndex >= ECHO_BUFFER_SIZE) readIndex = 0; //Update buffer length bufferLength -= n; //Total number of bytes sent txByteCount += n; } } //Adjust timeout value socketSetTimeout(context->socket, ECHO_TIMEOUT); //Graceful shutdown socketShutdown(context->socket, SOCKET_SD_BOTH); //Compute total duration duration = osGetTickCount() - startTime; //Debug message TRACE_INFO("Echo service: %u bytes received, %u bytes sent in %lu ms\r\n", rxByteCount, txByteCount, duration); //Close socket socketClose(context->socket); //Release previously allocated memory osMemFree(context); //Kill ourselves osTaskDelete(NULL); }
void Socket::handleSendError(int ret, const char* context) { #if defined(_WIN32) const int mongo_errno = WSAGetLastError(); if ( mongo_errno == WSAETIMEDOUT && _timeout != 0 ) { #else const int mongo_errno = errno; if ( ( mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK ) && _timeout != 0 ) { #endif LOG(_logLevel) << "Socket " << context << " send() timed out " << remoteString() << endl; throw SocketException(SocketException::SEND_TIMEOUT , remoteString()); } else { LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription(mongo_errno) << ' ' << remoteString() << endl; throw SocketException(SocketException::SEND_ERROR , remoteString()); } } void Socket::handleRecvError(int ret, int len) { if (ret == 0) { LOG(3) << "Socket recv() conn closed? " << remoteString() << endl; throw SocketException(SocketException::CLOSED , remoteString()); } // ret < 0 #if defined(_WIN32) int e = WSAGetLastError(); #else int e = errno; # if defined(EINTR) if (e == EINTR) { LOG(_logLevel) << "EINTR returned from recv(), retrying"; return; } # endif #endif #if defined(_WIN32) // Windows if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) { #else if (e == EAGAIN && _timeout > 0) { #endif // this is a timeout LOG(_logLevel) << "Socket recv() timeout " << remoteString() <<endl; throw SocketException(SocketException::RECV_TIMEOUT, remoteString()); } LOG(_logLevel) << "Socket recv() " << errnoWithDescription(e) << " " << remoteString() <<endl; throw SocketException(SocketException::RECV_ERROR , remoteString()); } void Socket::setTimeout( double secs ) { setSockTimeouts( _fd, secs ); } // TODO: allow modification? // // <positive value> : secs to wait between stillConnected checks // 0 : always check // -1 : never check const int Socket::errorPollIntervalSecs( 5 ); // Patch to allow better tolerance of flaky network connections that get broken // while we aren't looking. // TODO: Remove when better async changes come. // // isStillConnected() polls the socket at max every Socket::errorPollIntervalSecs to determine // if any disconnection-type events have happened on the socket. bool Socket::isStillConnected() { if (_fd == -1) { // According to the man page, poll will respond with POLLVNAL for invalid or // unopened descriptors, but it doesn't seem to be properly implemented in // some platforms - it can return 0 events and 0 for revent. Hence this workaround. return false; } if ( errorPollIntervalSecs < 0 ) return true; if ( ! isPollSupported() ) return true; // nothing we can do time_t now = time( 0 ); time_t idleTimeSecs = now - _lastValidityCheckAtSecs; // Only check once every 5 secs if ( idleTimeSecs < errorPollIntervalSecs ) return true; // Reset our timer, we're checking the connection _lastValidityCheckAtSecs = now; // It's been long enough, poll to see if our socket is still connected pollfd pollInfo; pollInfo.fd = _fd; // We only care about reading the EOF message on clean close (and errors) pollInfo.events = POLLIN; // Poll( info[], size, timeout ) - timeout == 0 => nonblocking int nEvents = socketPoll( &pollInfo, 1, 0 ); LOG( 2 ) << "polling for status of connection to " << remoteString() << ", " << ( nEvents == 0 ? "no events" : nEvents == -1 ? "error detected" : "event detected" ) << endl; if ( nEvents == 0 ) { // No events incoming, return still connected AFAWK return true; } else if ( nEvents < 0 ) { // Poll itself failed, this is weird, warn and log errno warning() << "Socket poll() failed during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << causedBy(errnoWithDescription()) << endl; // Return true since it's not clear that we're disconnected. return true; } dassert( nEvents == 1 ); dassert( pollInfo.revents > 0 ); // Return false at this point, some event happened on the socket, but log what the // actual event was. if ( pollInfo.revents & POLLIN ) { // There shouldn't really be any data to recv here, so make sure this // is a clean hangup. const int testBufLength = 1024; char testBuf[testBufLength]; int recvd = ::recv( _fd, testBuf, testBufLength, portRecvFlags ); if ( recvd < 0 ) { // An error occurred during recv, warn and log errno warning() << "Socket recv() failed during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << causedBy(errnoWithDescription()) << endl; } else if ( recvd > 0 ) { // We got nonzero data from this socket, very weird? // Log and warn at runtime, log and abort at devtime // TODO: Dump the data to the log somehow? error() << "Socket found pending " << recvd << " bytes of data during connectivity check" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; DEV { std::string hex = hexdump(testBuf, recvd); error() << "Hex dump of stale log data: " << hex << endl; } dassert( false ); } else { // recvd == 0, socket closed remotely, just return false LOG( 0 ) << "Socket closed remotely, no longer connected" << " (idle " << idleTimeSecs << " secs," << " remote host " << remoteString() << ")" << endl; } }
bool Socket::connect(SockAddr& remote) { _remote = remote; _fd = ::socket(remote.getType(), SOCK_STREAM, 0); if (_fd == INVALID_SOCKET) { networkWarnWithDescription(*this, "socket"); return false; } if (!setBlock(_fd, false)) { networkWarnWithDescription(*this, "set socket to non-blocking mode"); return false; } const Milliseconds connectTimeoutMillis(static_cast<int64_t>( _timeout > 0 ? std::min(kMaxConnectTimeoutMS, (_timeout * 1000)) : kMaxConnectTimeoutMS)); const Date_t expiration = Date_t::now() + connectTimeoutMillis; bool connectSucceeded = ::connect(_fd, _remote.raw(), _remote.addressSize) == 0; if (!connectSucceeded) { #ifdef _WIN32 if (WSAGetLastError() != WSAEWOULDBLOCK) { networkWarnWithDescription(*this, "connect"); return false; } #else if (errno != EINTR && errno != EINPROGRESS) { networkWarnWithDescription(*this, "connect"); return false; } #endif pollfd pfd; pfd.fd = _fd; pfd.events = POLLOUT; while (true) { const auto timeout = std::max(Milliseconds(0), expiration - Date_t::now()); int pollReturn = socketPoll(&pfd, 1, timeout.count()); #ifdef _WIN32 if (pollReturn == SOCKET_ERROR) { networkWarnWithDescription(*this, "poll"); return false; } #else if (pollReturn == -1) { if (errno != EINTR) { networkWarnWithDescription(*this, "poll"); return false; } // EINTR in poll, try again continue; } #endif // No activity for the full duration of the timeout. if (pollReturn == 0) { warning() << "Failed to connect to " << _remote.getAddr() << ":" << _remote.getPort() << " after " << connectTimeoutMillis << " milliseconds, giving up."; return false; } // We had a result, see if there's an error on the socket. int optVal; socklen_t optLen = sizeof(optVal); if (::getsockopt( _fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&optVal), &optLen) == -1) { networkWarnWithDescription(*this, "getsockopt"); return false; } if (optVal != 0) { networkWarnWithDescription(*this, "checking socket for error after poll", optVal); return false; } // We had activity and we don't have errors on the socket, we're connected. break; } } if (!setBlock(_fd, true)) { networkWarnWithDescription(*this, "could not set socket to blocking mode"); return false; } if (_timeout > 0) { setTimeout(_timeout); } if (remote.getType() != AF_UNIX) disableNagle(_fd); #ifdef SO_NOSIGPIPE // ignore SIGPIPE signals on osx, to avoid process exit const int one = 1; setsockopt(_fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int)); #endif _local = getLocalAddrForBoundSocketFd(_fd); _fdCreationMicroSec = curTimeMicros64(); _awaitingHandshake = false; return true; }