am 8050a02b: DO NOT MERGE: Linux sockets are odd, closing a socket descriptor does not abort pending recv/send calls.
* commit '8050a02b0130f0ba2e2ddfc240aa59029ee2ac6d': DO NOT MERGE: Linux sockets are odd, closing a socket descriptor does not abort pending recv/send calls.
This commit is contained in:
@@ -124,6 +124,80 @@ static status_t MyConnect(
|
|||||||
return result;
|
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) {
|
status_t HTTPStream::connect(const char *server, int port) {
|
||||||
Mutex::Autolock autoLock(mLock);
|
Mutex::Autolock autoLock(mLock);
|
||||||
|
|
||||||
@@ -220,16 +294,12 @@ status_t HTTPStream::send(const char *data, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
ssize_t n = ::send(mSocket, data, size, 0);
|
ssize_t n = MySend(mSocket, data, size, 0);
|
||||||
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
if (errno == EINTR) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
||||||
return ERROR_IO;
|
return n;
|
||||||
} else if (n == 0) {
|
} else if (n == 0) {
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
||||||
@@ -265,12 +335,8 @@ status_t HTTPStream::receive_line(char *line, size_t size) {
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char c;
|
char c;
|
||||||
ssize_t n = recv(mSocket, &c, 1, 0);
|
ssize_t n = MyReceive(mSocket, &c, 1, 0);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
if (errno == EINTR) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
||||||
return ERROR_IO;
|
return ERROR_IO;
|
||||||
@@ -383,14 +449,10 @@ status_t HTTPStream::receive_header(int *http_status) {
|
|||||||
ssize_t HTTPStream::receive(void *data, size_t size) {
|
ssize_t HTTPStream::receive(void *data, size_t size) {
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
while (total < size) {
|
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 (n < 0) {
|
||||||
if (errno == EINTR) {
|
LOGE("recv failed, errno = %d (%s)", (int)n, strerror(-n));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGE("recv failed, errno = %d (%s)", errno, strerror(errno));
|
|
||||||
|
|
||||||
disconnect();
|
disconnect();
|
||||||
return (ssize_t)ERROR_IO;
|
return (ssize_t)ERROR_IO;
|
||||||
|
|||||||
Reference in New Issue
Block a user