summaryrefslogtreecommitdiffstats
path: root/media/libstagefright
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2011-01-26 10:14:38 -0800
committerAndreas Huber <andih@google.com>2011-01-26 10:14:38 -0800
commit231640950ebd5accb7760ef0858f968d2c62a4dd (patch)
treef62dfbf880c50a6a9f2d4cd7a30a071b9b20bcec /media/libstagefright
parentff3b3ade7fa1da60d391d1a746cdc0868c24f4bf (diff)
downloadframeworks_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.cpp96
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;