Beispiel #1
0
Sint32 Socket::write(SocketHandle socket, const void* ptr, Uint32 size)
{
#ifdef PEGASUS_OS_TYPE_WINDOWS
    return ::send(socket, (const char*)ptr, size, 0);
#else
    int status;
    PEGASUS_RETRY_SYSTEM_CALL(::write(socket, (char*)ptr, size), status);
    return status;
#endif
}
Beispiel #2
0
void Socket::close(SocketHandle& socket)
{
    if (socket != PEGASUS_INVALID_SOCKET)
    {
#ifdef PEGASUS_OS_TYPE_WINDOWS
        if (!closesocket(socket))
        {
            socket = PEGASUS_INVALID_SOCKET;
        }
#else
        int status;
        PEGASUS_RETRY_SYSTEM_CALL(::close(socket), status);

        if (status == 0)
        {
            socket = PEGASUS_INVALID_SOCKET;
        }
#endif
    }
}
Beispiel #3
0
Boolean Socket::timedConnect(
    SocketHandle socket,
    sockaddr* address,
    int addressLength,
    Uint32 timeoutMilliseconds)
{
    int connectResult;
#ifdef PEGASUS_OS_TYPE_WINDOWS
    connectResult = ::connect(socket, address, addressLength);
#else
    Boolean connectionAlreadyRefused = false;
    Uint32 maxConnectAttempts = 100;
    // Retry the connect() until it succeeds or it fails with an error other
    // than EINTR, EAGAIN (for Linux), or the first ECONNREFUSED (for HP-UX).
    while (((connectResult = ::connect(socket, address, addressLength)) == -1)
           && (maxConnectAttempts-- > 0)
           && ((errno == EINTR) || (errno == EAGAIN) ||
               ((errno == ECONNREFUSED) && !connectionAlreadyRefused)))
    {
        if (errno == ECONNREFUSED)
        {
            connectionAlreadyRefused = true;
        }
        Threads::sleep(1);
    }
#endif

    if (connectResult == 0)
    {
        return true;
    }

    if (getSocketError() == PEGASUS_NETWORK_EINPROGRESS)
    {
        PEG_TRACE((TRC_HTTP, Tracer::LEVEL4,
            "Connection to server in progress.  Waiting up to %u milliseconds "
                "for the socket to become connected.",
            timeoutMilliseconds));

        fd_set fdwrite;
        FD_ZERO(&fdwrite);
        FD_SET(socket, &fdwrite);
        struct timeval timeoutValue =
            { timeoutMilliseconds/1000, timeoutMilliseconds%1000*1000 };
        int selectResult = -1;

#ifdef PEGASUS_OS_TYPE_WINDOWS
        PEGASUS_RETRY_SYSTEM_CALL(
            select(FD_SETSIZE, NULL, &fdwrite, &fdwrite, &timeoutValue),
            selectResult);
#else
        PEGASUS_RETRY_SYSTEM_CALL(
            select(FD_SETSIZE, NULL, &fdwrite, NULL, &timeoutValue),
            selectResult);
#endif
        if (selectResult == 0)
        {
            PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
                "select() timed out waiting for the socket connection to be "
                    "established.");
            return false;
        }
        else if (selectResult > 0)
        {
            int optval;
            SocketLength optlen = sizeof(int);
            getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen);
            if (optval == 0)
            {
                PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL4,
                    "Connection with server established.");
                return true;
            }
            else
            {
                PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
                    "Did not connect, getsockopt() returned optval = %d",
                    optval));
                return false;
            }
        }
        else
        {
            PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
                "select() returned error code %d",
                getSocketError()));
            return false;
        }
    }

    PEG_TRACE((TRC_HTTP, Tracer::LEVEL1,
        "connect() returned error code %d",
        getSocketError()));
    return false;
}
Beispiel #4
0
Sint32 Socket::timedWrite(
    SocketHandle socket,
    const void* ptr,
    Uint32 size,
    Uint32 socketWriteTimeout)
{
    Sint32 bytesWritten = 0;
    Sint32 totalBytesWritten = 0;
    Boolean socketTimedOut = false;
    int selreturn = 0;
    while (1)
    {
#ifdef PEGASUS_OS_TYPE_WINDOWS
        PEGASUS_RETRY_SYSTEM_CALL(
            ::send(socket, (const char*)ptr, size, 0), bytesWritten);
#else
        PEGASUS_RETRY_SYSTEM_CALL(
            ::write(socket, (char*)ptr, size), bytesWritten);
#endif
        // Some data written this cycle ?
        // Add it to the total amount of written data.
        if (bytesWritten > 0)
        {
            totalBytesWritten += bytesWritten;
            socketTimedOut = false;
        }

        // All data written ? return amount of data written
        if ((Uint32)bytesWritten == size)
        {
            return totalBytesWritten;
        }
        // If data has been written partially, we resume writing data
        // this also accounts for the case of a signal interrupt
        // (i.e. errno = EINTR)
        if (bytesWritten > 0)
        {
            size -= bytesWritten;
            ptr = (void *)((char *)ptr + bytesWritten);
            continue;
        }
        // Something went wrong
        if (bytesWritten == PEGASUS_SOCKET_ERROR)
        {
            // if we already waited for the socket to get ready, bail out
            if (socketTimedOut) return bytesWritten;
#ifdef PEGASUS_OS_TYPE_WINDOWS
            if (WSAGetLastError() == WSAEWOULDBLOCK)
#else
            if (errno == EAGAIN || errno == EWOULDBLOCK)
#endif
            {
                fd_set fdwrite;
                 // max. timeout seconds waiting for the socket to get ready
                struct timeval tv = { socketWriteTimeout, 0 };
                FD_ZERO(&fdwrite);
                FD_SET(socket, &fdwrite);
                selreturn = select(FD_SETSIZE, NULL, &fdwrite, NULL, &tv);
                if (selreturn == 0) socketTimedOut = true; // ran out of time
                continue;
            }
            return bytesWritten;
        }
    }
}
Beispiel #5
0
Sint32 SSLSocket::connect(Uint32 timeoutMilliseconds)
{
    PEG_METHOD_ENTER(TRC_SSL, "SSLSocket::connect()");

    PEG_TRACE((TRC_SSL, Tracer::LEVEL4,
        "Connection timeout in milliseconds is : %d", timeoutMilliseconds));

    SSL* sslConnection = static_cast<SSL*>(_SSLConnection);
    SSL_set_connect_state(sslConnection);

    while (1)
    {
        int ssl_rc = SSL_connect(sslConnection);

        if (ssl_rc > 0)
        {
            // Connected!
            break;
        }

        if (ssl_rc == 0)
        {
            PEG_TRACE((
                TRC_SSL,
                Tracer::LEVEL1,
                "---> SSL: Shutdown SSL_connect() failed. Error string: %s",
                ERR_error_string(ssl_rc, NULL)));

            PEG_METHOD_EXIT();
            return -1;
        }

        // Error case:  ssl_rc < 0

        int ssl_rsn = SSL_get_error(sslConnection, ssl_rc);

        if ((ssl_rsn == SSL_ERROR_SYSCALL) &&
            ((errno == EAGAIN) || (errno == EINTR)))
        {
            // Temporary error; retry the SSL_connect()
            continue;
        }

        if ((ssl_rsn != SSL_ERROR_WANT_READ) &&
            (ssl_rsn != SSL_ERROR_WANT_WRITE))
        {
            // Error, connection failed
            if (Tracer::isTraceOn())
            {
                unsigned long rc = ERR_get_error ();
                char buff[256];
                // added in OpenSSL 0.9.6:
                ERR_error_string_n(rc, buff, sizeof(buff));
                PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL1,
                    "---> SSL: Not connected %d %s", ssl_rsn, buff));
            }

            PEG_METHOD_EXIT();
            return -1;
        }

        // Wait until the socket is ready for reading or writing (as
        // appropriate) and then retry the SSL_connect()

        fd_set fd;
        FD_ZERO(&fd);
        FD_SET(_socket, &fd);
        struct timeval timeoutValue =
            { timeoutMilliseconds/1000, timeoutMilliseconds%1000*1000 };
        int selectResult = -1;

        if (ssl_rsn == SSL_ERROR_WANT_READ)
        {
            PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL4,
                "---> SSL: Retry WANT_READ");
            PEGASUS_RETRY_SYSTEM_CALL(
                select(FD_SETSIZE, &fd, NULL, NULL, &timeoutValue),
                selectResult);
        }
        else    // (ssl_rsn == SSL_ERROR_WANT_WRITE)
        {
            PEGASUS_ASSERT(ssl_rsn == SSL_ERROR_WANT_WRITE);
            PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL4,
                "---> SSL: Retry WANT_WRITE");
            PEGASUS_RETRY_SYSTEM_CALL(
                select(FD_SETSIZE, NULL, &fd, NULL, &timeoutValue),
                selectResult);
        }

        // Check the result of select.
        if (selectResult == 0)
        {
            PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
                "---> SSL: Failed to connect, connection timed out.");
            PEG_METHOD_EXIT();
            return -1;
        }
        else if (selectResult == PEGASUS_SOCKET_ERROR)
        {
            PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL1,
                "---> SSL: Failed to connect, select error, return code = %d",
                selectResult));
            PEG_METHOD_EXIT();
            return -1;
        }
        // else retry the SSL_connect()
    }

    PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3, "---> SSL: Connected");

    if (_SSLContext->isPeerVerificationEnabled())
    {
        PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL4,
           "Attempting to verify server certificate.");

        X509* server_cert = SSL_get_peer_certificate(sslConnection);
        if (server_cert != NULL)
        {
            //
            // Do not check the verification result using
            // SSL_get_verify_result here to see whether or not to continue.
            // The prepareForCallback does not reset the verification result,
            // so it will still contain the original error.  If the client
            // chose to override the default error in the callback and
            // return true, we got here and should proceed with the
            // transaction.  Otherwise, the handshake was already terminated.
            //

            if (SSL_get_verify_result(sslConnection) == X509_V_OK)
            {
                 PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL4,
                     "--->SSL: Server Certificate verified.");
            }
            else
            {
                PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL4,
                     "--->SSL: Server Certificate not verified, but the "
                         "callback overrode the default error.");
            }

            X509_free (server_cert);
        }
        else
        {
            PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL1,
                "-->SSL: Server not certified, no certificate received.");
            PEG_METHOD_EXIT();
            return -1;
        }
    }
    else
    {
        PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL4,
            "---> SSL: Server certification disabled");
    }

    PEG_METHOD_EXIT();
    return 1;
}