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;
}
Exemple #2
0
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);
         }
      }
   }
}
Exemple #3
0
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);
}
Exemple #4
0
    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;
            }
        }
Exemple #5
0
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;
}