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

Commit 8050a02b authored by Andreas Huber's avatar Andreas Huber Committed by Jean-Baptiste Queru
Browse files

DO NOT MERGE: Linux sockets are odd, closing a socket descriptor does not...

DO NOT MERGE: Linux sockets are odd, closing a socket descriptor does not abort pending recv/send calls.

Change-Id: Iaee1821257a25a5257d93c9f5ba3976748cad619
related-to-bug: 3362836, 4439092
parent 0aa1017f
Loading
Loading
Loading
Loading
+79 −17
Original line number Diff line number Diff line
@@ -124,6 +124,80 @@ static status_t MyConnect(
    return result;
}

// Apparently under our linux closing a socket descriptor from one thread
// will not unblock a pending send/recv on that socket on another thread.
static ssize_t MySendReceive(
        int s, void *data, size_t size, int flags, bool sendData) {
    ssize_t result = 0;

    while (size > 0) {
        fd_set rs, ws, es;
        FD_ZERO(&rs);
        FD_ZERO(&ws);
        FD_ZERO(&es);
        FD_SET(s, sendData ? &ws : &rs);
        FD_SET(s, &es);

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

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

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

            result = -errno;
            break;
        } else if (nfds == 0) {
            // timeout

            continue;
        }

        CHECK_EQ(nfds, 1);

        ssize_t nbytes =
            sendData ? send(s, data, size, flags) : recv(s, data, size, flags);

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

            result = -errno;
            break;
        } else if (nbytes == 0) {
            result = 0;
            break;
        }

        data = (uint8_t *)data + nbytes;
        size -= nbytes;

        result = nbytes;
        break;
    }

    return result;
}

static ssize_t MySend(int s, const void *data, size_t size, int flags) {
    return MySendReceive(
            s, const_cast<void *>(data), size, flags, true /* sendData */);
}

static ssize_t MyReceive(int s, void *data, size_t size, int flags) {
    return MySendReceive(s, data, size, flags, false /* sendData */);
}

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

@@ -220,16 +294,12 @@ status_t HTTPStream::send(const char *data, size_t size) {
    }

    while (size > 0) {
        ssize_t n = ::send(mSocket, data, size, 0);
        ssize_t n = MySend(mSocket, data, size, 0);

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

            disconnect();

            return ERROR_IO;
            return n;
        } else if (n == 0) {
            disconnect();

@@ -265,12 +335,8 @@ status_t HTTPStream::receive_line(char *line, size_t size) {

    for (;;) {
        char c;
        ssize_t n = recv(mSocket, &c, 1, 0);
        ssize_t n = MyReceive(mSocket, &c, 1, 0);
        if (n < 0) {
            if (errno == EINTR) {
                continue;
            }

            disconnect();

            return ERROR_IO;
@@ -383,14 +449,10 @@ status_t HTTPStream::receive_header(int *http_status) {
ssize_t HTTPStream::receive(void *data, size_t size) {
    size_t total = 0;
    while (total < size) {
        ssize_t n = recv(mSocket, (char *)data + total, size - total, 0);
        ssize_t n = MyReceive(mSocket, (char *)data + total, size - total, 0);

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

            LOGE("recv failed, errno = %d (%s)", errno, strerror(errno));
            LOGE("recv failed, errno = %d (%s)", (int)n, strerror(-n));

            disconnect();
            return (ssize_t)ERROR_IO;