diff options
author | Andreas Huber <andih@google.com> | 2011-01-18 15:26:40 -0800 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2011-01-18 15:52:31 -0800 |
commit | f4c056aeacad2dac60a83ccd7928bfeaa9d6ddf6 (patch) | |
tree | 33c73abc7fb95445121cc4595a863ed45000b29e /media | |
parent | 95304d5488ba465f19cc788f1c7394218c2ea2d1 (diff) | |
download | frameworks_av-f4c056aeacad2dac60a83ccd7928bfeaa9d6ddf6.zip frameworks_av-f4c056aeacad2dac60a83ccd7928bfeaa9d6ddf6.tar.gz frameworks_av-f4c056aeacad2dac60a83ccd7928bfeaa9d6ddf6.tar.bz2 |
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
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/HTTPStream.cpp | 85 |
1 files changed, 81 insertions, 4 deletions
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp index ccc6a34..7194614 100644 --- a/media/libstagefright/HTTPStream.cpp +++ b/media/libstagefright/HTTPStream.cpp @@ -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; |