Commit 6f068498 authored by Subodh Iyengar's avatar Subodh Iyengar Committed by Facebook Github Bot 0

Fix cases of overwriting errno

Summary:AsyncSocket has a few cases where
we might overwrite errno, with another function
call that is done during use.

For example withAddr could cause an EBADF if the fd
was bad.

This fixes these cases by copying errno, before doing
anything else

Reviewed By: afrind

Differential Revision: D3101932

fb-gh-sync-id: 73d4810314c90cb987936a0a3a9dc977af07243a
fbshipit-source-id: 73d4810314c90cb987936a0a3a9dc977af07243a
parent 03343ccb
...@@ -298,9 +298,11 @@ void AsyncSocket::setShutdownSocketSet(ShutdownSocketSet* newSS) { ...@@ -298,9 +298,11 @@ void AsyncSocket::setShutdownSocketSet(ShutdownSocketSet* newSS) {
void AsyncSocket::setCloseOnExec() { void AsyncSocket::setCloseOnExec() {
int rv = fcntl(fd_, F_SETFD, FD_CLOEXEC); int rv = fcntl(fd_, F_SETFD, FD_CLOEXEC);
if (rv != 0) { if (rv != 0) {
throw AsyncSocketException(AsyncSocketException::INTERNAL_ERROR, auto errnoCopy = errno;
throw AsyncSocketException(
AsyncSocketException::INTERNAL_ERROR,
withAddr("failed to set close-on-exec flag"), withAddr("failed to set close-on-exec flag"),
errno); errnoCopy);
} }
} }
...@@ -338,8 +340,11 @@ void AsyncSocket::connect(ConnectCallback* callback, ...@@ -338,8 +340,11 @@ void AsyncSocket::connect(ConnectCallback* callback,
// implementations the PF_foo and AF_foo constants are identical. // implementations the PF_foo and AF_foo constants are identical.
fd_ = socket(address.getFamily(), SOCK_STREAM, 0); fd_ = socket(address.getFamily(), SOCK_STREAM, 0);
if (fd_ < 0) { if (fd_ < 0) {
throw AsyncSocketException(AsyncSocketException::INTERNAL_ERROR, auto errnoCopy = errno;
withAddr("failed to create socket"), errno); throw AsyncSocketException(
AsyncSocketException::INTERNAL_ERROR,
withAddr("failed to create socket"),
errnoCopy);
} }
if (shutdownSocketSet_) { if (shutdownSocketSet_) {
shutdownSocketSet_->add(fd_); shutdownSocketSet_->add(fd_);
...@@ -351,25 +356,30 @@ void AsyncSocket::connect(ConnectCallback* callback, ...@@ -351,25 +356,30 @@ void AsyncSocket::connect(ConnectCallback* callback,
// Put the socket in non-blocking mode // Put the socket in non-blocking mode
int flags = fcntl(fd_, F_GETFL, 0); int flags = fcntl(fd_, F_GETFL, 0);
if (flags == -1) { if (flags == -1) {
throw AsyncSocketException(AsyncSocketException::INTERNAL_ERROR, auto errnoCopy = errno;
withAddr("failed to get socket flags"), errno); throw AsyncSocketException(
AsyncSocketException::INTERNAL_ERROR,
withAddr("failed to get socket flags"),
errnoCopy);
} }
int rv = fcntl(fd_, F_SETFL, flags | O_NONBLOCK); int rv = fcntl(fd_, F_SETFL, flags | O_NONBLOCK);
if (rv == -1) { if (rv == -1) {
auto errnoCopy = errno;
throw AsyncSocketException( throw AsyncSocketException(
AsyncSocketException::INTERNAL_ERROR, AsyncSocketException::INTERNAL_ERROR,
withAddr("failed to put socket in non-blocking mode"), withAddr("failed to put socket in non-blocking mode"),
errno); errnoCopy);
} }
#if !defined(MSG_NOSIGNAL) && defined(F_SETNOSIGPIPE) #if !defined(MSG_NOSIGNAL) && defined(F_SETNOSIGPIPE)
// iOS and OS X don't support MSG_NOSIGNAL; set F_SETNOSIGPIPE instead // iOS and OS X don't support MSG_NOSIGNAL; set F_SETNOSIGPIPE instead
rv = fcntl(fd_, F_SETNOSIGPIPE, 1); rv = fcntl(fd_, F_SETNOSIGPIPE, 1);
if (rv == -1) { if (rv == -1) {
auto errnoCopy = errno;
throw AsyncSocketException( throw AsyncSocketException(
AsyncSocketException::INTERNAL_ERROR, AsyncSocketException::INTERNAL_ERROR,
"failed to enable F_SETNOSIGPIPE on socket", "failed to enable F_SETNOSIGPIPE on socket",
errno); errnoCopy);
} }
#endif #endif
...@@ -387,21 +397,23 @@ void AsyncSocket::connect(ConnectCallback* callback, ...@@ -387,21 +397,23 @@ void AsyncSocket::connect(ConnectCallback* callback,
if (bindAddr != anyAddress()) { if (bindAddr != anyAddress()) {
int one = 1; int one = 1;
if (::setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { if (::setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
auto errnoCopy = errno;
doClose(); doClose();
throw AsyncSocketException( throw AsyncSocketException(
AsyncSocketException::NOT_OPEN, AsyncSocketException::NOT_OPEN,
"failed to setsockopt prior to bind on " + bindAddr.describe(), "failed to setsockopt prior to bind on " + bindAddr.describe(),
errno); errnoCopy);
} }
bindAddr.getAddress(&addrStorage); bindAddr.getAddress(&addrStorage);
if (::bind(fd_, saddr, bindAddr.getActualSize()) != 0) { if (::bind(fd_, saddr, bindAddr.getActualSize()) != 0) {
auto errnoCopy = errno;
doClose(); doClose();
throw AsyncSocketException(AsyncSocketException::NOT_OPEN, throw AsyncSocketException(
"failed to bind to async socket: " + AsyncSocketException::NOT_OPEN,
bindAddr.describe(), "failed to bind to async socket: " + bindAddr.describe(),
errno); errnoCopy);
} }
} }
...@@ -409,9 +421,11 @@ void AsyncSocket::connect(ConnectCallback* callback, ...@@ -409,9 +421,11 @@ void AsyncSocket::connect(ConnectCallback* callback,
for (const auto& opt: options) { for (const auto& opt: options) {
int rv = opt.first.apply(fd_, opt.second); int rv = opt.first.apply(fd_, opt.second);
if (rv != 0) { if (rv != 0) {
throw AsyncSocketException(AsyncSocketException::INTERNAL_ERROR, auto errnoCopy = errno;
throw AsyncSocketException(
AsyncSocketException::INTERNAL_ERROR,
withAddr("failed to set socket option"), withAddr("failed to set socket option"),
errno); errnoCopy);
} }
} }
...@@ -420,7 +434,8 @@ void AsyncSocket::connect(ConnectCallback* callback, ...@@ -420,7 +434,8 @@ void AsyncSocket::connect(ConnectCallback* callback,
rv = ::connect(fd_, saddr, address.getActualSize()); rv = ::connect(fd_, saddr, address.getActualSize());
if (rv < 0) { if (rv < 0) {
if (errno == EINPROGRESS) { auto errnoCopy = errno;
if (errnoCopy == EINPROGRESS) {
// Connection in progress. // Connection in progress.
if (timeout > 0) { if (timeout > 0) {
// Start a timer in case the connection takes too long. // Start a timer in case the connection takes too long.
...@@ -441,8 +456,10 @@ void AsyncSocket::connect(ConnectCallback* callback, ...@@ -441,8 +456,10 @@ void AsyncSocket::connect(ConnectCallback* callback,
} }
return; return;
} else { } else {
throw AsyncSocketException(AsyncSocketException::NOT_OPEN, throw AsyncSocketException(
"connect failed (immediately)", errno); AsyncSocketException::NOT_OPEN,
"connect failed (immediately)",
errnoCopy);
} }
} }
...@@ -679,8 +696,11 @@ void AsyncSocket::writeImpl(WriteCallback* callback, const iovec* vec, ...@@ -679,8 +696,11 @@ void AsyncSocket::writeImpl(WriteCallback* callback, const iovec* vec,
bytesWritten = performWrite(vec, count, flags, bytesWritten = performWrite(vec, count, flags,
&countWritten, &partialWritten); &countWritten, &partialWritten);
if (bytesWritten < 0) { if (bytesWritten < 0) {
AsyncSocketException ex(AsyncSocketException::INTERNAL_ERROR, auto errnoCopy = errno;
withAddr("writev failed"), errno); AsyncSocketException ex(
AsyncSocketException::INTERNAL_ERROR,
withAddr("writev failed"),
errnoCopy);
return failWrite(__func__, callback, 0, ex); return failWrite(__func__, callback, 0, ex);
} else if (countWritten == count) { } else if (countWritten == count) {
// We successfully wrote everything. // We successfully wrote everything.
...@@ -1355,8 +1375,11 @@ void AsyncSocket::handleRead() noexcept { ...@@ -1355,8 +1375,11 @@ void AsyncSocket::handleRead() noexcept {
return; return;
} else if (bytesRead == READ_ERROR) { } else if (bytesRead == READ_ERROR) {
readErr_ = READ_ERROR; readErr_ = READ_ERROR;
AsyncSocketException ex(AsyncSocketException::INTERNAL_ERROR, auto errnoCopy = errno;
withAddr("recv() failed"), errno); AsyncSocketException ex(
AsyncSocketException::INTERNAL_ERROR,
withAddr("recv() failed"),
errnoCopy);
return failRead(__func__, ex); return failRead(__func__, ex);
} else { } else {
assert(bytesRead == READ_EOF); assert(bytesRead == READ_EOF);
...@@ -1416,8 +1439,11 @@ void AsyncSocket::handleWrite() noexcept { ...@@ -1416,8 +1439,11 @@ void AsyncSocket::handleWrite() noexcept {
EventBase* originalEventBase = eventBase_; EventBase* originalEventBase = eventBase_;
while (writeReqHead_ != nullptr && eventBase_ == originalEventBase) { while (writeReqHead_ != nullptr && eventBase_ == originalEventBase) {
if (!writeReqHead_->performWrite()) { if (!writeReqHead_->performWrite()) {
AsyncSocketException ex(AsyncSocketException::INTERNAL_ERROR, auto errnoCopy = errno;
withAddr("writev() failed"), errno); AsyncSocketException ex(
AsyncSocketException::INTERNAL_ERROR,
withAddr("writev() failed"),
errnoCopy);
return failWrite(__func__, ex); return failWrite(__func__, ex);
} else if (writeReqHead_->isComplete()) { } else if (writeReqHead_->isComplete()) {
// We finished this request // We finished this request
...@@ -1591,9 +1617,11 @@ void AsyncSocket::handleConnect() noexcept { ...@@ -1591,9 +1617,11 @@ void AsyncSocket::handleConnect() noexcept {
socklen_t len = sizeof(error); socklen_t len = sizeof(error);
int rv = getsockopt(fd_, SOL_SOCKET, SO_ERROR, &error, &len); int rv = getsockopt(fd_, SOL_SOCKET, SO_ERROR, &error, &len);
if (rv != 0) { if (rv != 0) {
AsyncSocketException ex(AsyncSocketException::INTERNAL_ERROR, auto errnoCopy = errno;
AsyncSocketException ex(
AsyncSocketException::INTERNAL_ERROR,
withAddr("error calling getsockopt() after connect"), withAddr("error calling getsockopt() after connect"),
errno); errnoCopy);
VLOG(4) << "AsyncSocket::handleConnect(this=" << this << ", fd=" VLOG(4) << "AsyncSocket::handleConnect(this=" << this << ", fd="
<< fd_ << " host=" << addr_.describe() << fd_ << " host=" << addr_.describe()
<< ") exception:" << ex.what(); << ") exception:" << ex.what();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment