diff options
author | Andreas Huber <andih@google.com> | 2011-01-26 10:14:38 -0800 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2011-01-26 10:14:38 -0800 |
commit | 231640950ebd5accb7760ef0858f968d2c62a4dd (patch) | |
tree | f62dfbf880c50a6a9f2d4cd7a30a071b9b20bcec /media/libstagefright | |
parent | ff3b3ade7fa1da60d391d1a746cdc0868c24f4bf (diff) | |
download | frameworks_base-231640950ebd5accb7760ef0858f968d2c62a4dd.zip frameworks_base-231640950ebd5accb7760ef0858f968d2c62a4dd.tar.gz frameworks_base-231640950ebd5accb7760ef0858f968d2c62a4dd.tar.bz2 |
Linux sockets suck, closing a socket descriptor does not abort pending recv/send calls.
Change-Id: Id53e7831761619f72ddc61f63571230011c93f16
related-to-bug: 3362836
Diffstat (limited to 'media/libstagefright')
-rw-r--r-- | media/libstagefright/HTTPStream.cpp | 96 |
1 files changed, 79 insertions, 17 deletions
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp index 057868c..77a61a5 100644 --- a/media/libstagefright/HTTPStream.cpp +++ b/media/libstagefright/HTTPStream.cpp @@ -124,6 +124,80 @@ static status_t MyConnect( return result; } +// Apparently under out 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); @@ -202,16 +276,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(); @@ -247,12 +317,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; @@ -371,14 +437,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; |