summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2021-08-25 17:15:15 -0700
committerYifan Hong <elsk@google.com>2021-08-25 17:41:40 -0700
commit95d15e56fc1e45b1aa11e9ad6ce01f77f0a28c36 (patch)
treea8718a0219512ea367012118daf12efc697a05c6
parentab281ec6f1922fc5fd175223d739d01018131777 (diff)
downloadnative-95d15e56fc1e45b1aa11e9ad6ce01f77f0a28c36.tar.gz
binder: retry connect() on ECONNRESET for non-blocking sockets.
For non-blocking sockets, if connect() returns EAGAIN / EINPROGRESS, the code calls getsockopt() to get the real error if connect() were called with a blocking socket fd. If ECONNRESET is seen, also retry. Test: binderRpcTest Fixes: 197162885 Change-Id: I7c7b8cb105d0d334b75b883ffcff3b0c62337cf4
-rw-r--r--libs/binder/RpcSession.cpp56
1 files changed, 29 insertions, 27 deletions
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 4c47005c7a..3e9e5a8441 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -484,37 +484,39 @@ status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
}
if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
- if (errno == ECONNRESET) {
+ int connErrno = errno;
+ if (connErrno == EAGAIN || connErrno == EINPROGRESS) {
+ // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
+ // EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
+ status_t pollStatus = mShutdownTrigger->triggerablePoll(serverFd, POLLOUT);
+ if (pollStatus != OK) {
+ ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
+ statusToString(pollStatus).c_str());
+ return pollStatus;
+ }
+ // Set connErrno to the errno that connect() would have set if the fd were blocking.
+ socklen_t connErrnoLen = sizeof(connErrno);
+ int ret =
+ getsockopt(serverFd.get(), SOL_SOCKET, SO_ERROR, &connErrno, &connErrnoLen);
+ if (ret == -1) {
+ int savedErrno = errno;
+ ALOGE("Could not getsockopt() after connect() on non-blocking socket: %s. "
+ "(Original error from connect() is: %s)",
+ strerror(savedErrno), strerror(connErrno));
+ return -savedErrno;
+ }
+ // Retrieved the real connErrno as if connect() was called with a blocking socket
+ // fd. Continue checking connErrno.
+ }
+ if (connErrno == ECONNRESET) {
ALOGW("Connection reset on %s", addr.toString().c_str());
continue;
}
- if (errno != EAGAIN && errno != EINPROGRESS) {
- int savedErrno = errno;
+ // connErrno could be zero if getsockopt determines so. Hence zero-check again.
+ if (connErrno != 0) {
ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
- strerror(savedErrno));
- return -savedErrno;
- }
- // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
- // EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
- status_t pollStatus = mShutdownTrigger->triggerablePoll(serverFd, POLLOUT);
- if (pollStatus != OK) {
- ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
- statusToString(pollStatus).c_str());
- return pollStatus;
- }
- int soError;
- socklen_t soErrorLen = sizeof(soError);
- int ret = getsockopt(serverFd.get(), SOL_SOCKET, SO_ERROR, &soError, &soErrorLen);
- if (ret == -1) {
- int savedErrno = errno;
- ALOGE("Could not getsockopt() after connect() on non-blocking socket: %s",
- strerror(savedErrno));
- return -savedErrno;
- }
- if (soError != 0) {
- ALOGE("After connect(), getsockopt() returns error for socket at %s: %s",
- addr.toString().c_str(), strerror(soError));
- return -soError;
+ strerror(connErrno));
+ return -connErrno;
}
}
LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());