Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4c056ae authored by Andreas Huber's avatar Andreas Huber
Browse files

DO NOT MERGE: Apparently our native TCP sockets do not return an error from blocking "connect"

if the network interface is shutdown while connecting.

Change-Id: I168c6026de24812efa9b7e607a9eb83efded8c1f
related-to-bug: 3362836
parent 95304d54
Loading
Loading
Loading
Loading
+81 −4
Original line number Diff line number Diff line
@@ -25,13 +25,14 @@
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/foundation/ADebug.h>

namespace android {

@@ -47,6 +48,82 @@ HTTPStream::~HTTPStream() {
    disconnect();
}

static bool MakeSocketBlocking(int s, bool blocking) {
    // Make socket non-blocking.
    int flags = fcntl(s, F_GETFL, 0);
    if (flags == -1) {
        return false;
    }

    if (blocking) {
        flags &= ~O_NONBLOCK;
    } else {
        flags |= O_NONBLOCK;
    }

    return fcntl(s, F_SETFL, flags) != -1;
}

static status_t MyConnect(
        int s, const struct sockaddr *addr, socklen_t addrlen) {
    status_t result = UNKNOWN_ERROR;

    MakeSocketBlocking(s, false);

    if (connect(s, addr, addrlen) == 0) {
        result = OK;
    } else if (errno != EINPROGRESS) {
        result = -errno;
    } else {
        for (;;) {
            fd_set rs, ws;
            FD_ZERO(&rs);
            FD_ZERO(&ws);
            FD_SET(s, &rs);
            FD_SET(s, &ws);

            struct timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = 100000ll;

            int nfds = ::select(s + 1, &rs, &ws, NULL, &tv);

            if (nfds < 0) {
                if (errno == EINTR) {
                    continue;
                }

                result = -errno;
                break;
            }

            if (FD_ISSET(s, &ws) && !FD_ISSET(s, &rs)) {
                result = OK;
                break;
            }

            if (FD_ISSET(s, &rs) || FD_ISSET(s, &ws)) {
                // Get the pending error.
                int error = 0;
                socklen_t errorLen = sizeof(error);
                if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &errorLen) == -1) {
                    // Couldn't get the real error, so report why not.
                    result = -errno;
                } else {
                    result = -error;
                }
                break;
            }

            // Timeout expired. Try again.
        }
    }

    MakeSocketBlocking(s, true);

    return result;
}

status_t HTTPStream::connect(const char *server, int port) {
    Mutex::Autolock autoLock(mLock);

@@ -82,7 +159,7 @@ status_t HTTPStream::connect(const char *server, int port) {
    addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
    memset(addr.sin_zero, 0, sizeof(addr.sin_zero));

    int res = ::connect(s, (const struct sockaddr *)&addr, sizeof(addr));
    status_t res = MyConnect(s, (const struct sockaddr *)&addr, sizeof(addr));

    mLock.lock();

@@ -90,12 +167,12 @@ status_t HTTPStream::connect(const char *server, int port) {
        return UNKNOWN_ERROR;
    }

    if (res < 0) {
    if (res != OK) {
        close(mSocket);
        mSocket = -1;

        mState = READY;
        return UNKNOWN_ERROR;
        return res;
    }

    mState = CONNECTED;