Socket::Socket(int fd , const SockAddr& remote) : _fd(fd), _remote(remote), _timeout(0), _lastValidityCheckAtSecs(time(0)), _logLevel(logger::LogSeverity::Log()) { _init(); if (fd >= 0) { _local = getLocalAddrForBoundSocketFd(_fd); } }
bool Socket::connect(SockAddr& remote) { _remote = remote; _fd = socket(remote.getType(), SOCK_STREAM, 0); if ( _fd == INVALID_SOCKET ) { LOG(_logLevel) << "ERROR: connect invalid socket " << errnoWithDescription() << endl; return false; } if ( _timeout > 0 ) { setTimeout( _timeout ); } static const unsigned int connectTimeoutMillis = 5000; ConnectBG bg(_fd, remote); bg.go(); if ( bg.wait(connectTimeoutMillis) ) { if ( bg.inError() ) { warning() << "Failed to connect to " << _remote.getAddr() << ":" << _remote.getPort() << ", reason: " << bg.getErrnoWithDescription() << endl; close(); return false; } } else { // time out the connect close(); bg.wait(); // so bg stays in scope until bg thread terminates warning() << "Failed to connect to " << _remote.getAddr() << ":" << _remote.getPort() << " after " << connectTimeoutMillis << " milliseconds, giving up." << endl; return false; } if (remote.getType() != AF_UNIX) disableNagle(_fd); #ifdef SO_NOSIGPIPE // ignore SIGPIPE signals on osx, to avoid process exit const int one = 1; setsockopt( _fd , SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int)); #endif _local = getLocalAddrForBoundSocketFd(_fd); _fdCreationMicroSec = curTimeMicros64(); _awaitingHandshake = false; return true; }
bool Socket::connect(SockAddr& remote) { _remote = remote; _fd = socket(remote.getType(), SOCK_STREAM, 0); if ( _fd == INVALID_SOCKET ) { LOG(_logLevel) << "ERROR: connect invalid socket " << errnoWithDescription() << endl; return false; } if ( _timeout > 0 ) { setTimeout( _timeout ); } ConnectBG bg(_fd, remote); bg.go(); if ( bg.wait(5000) ) { if ( bg.inError() ) { close(); return false; } } else { // time out the connect close(); bg.wait(); // so bg stays in scope until bg thread terminates return false; } if (remote.getType() != AF_UNIX) disableNagle(_fd); #ifdef SO_NOSIGPIPE // ignore SIGPIPE signals on osx, to avoid process exit const int one = 1; setsockopt( _fd , SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int)); #endif _local = getLocalAddrForBoundSocketFd(_fd); _fdCreationMicroSec = curTimeMicros64(); return true; }
bool Socket::connect(SockAddr& remote) { _remote = remote; _fd = ::socket(remote.getType(), SOCK_STREAM, 0); if (_fd == INVALID_SOCKET) { networkWarnWithDescription(*this, "socket"); return false; } if (!setBlock(_fd, false)) { networkWarnWithDescription(*this, "set socket to non-blocking mode"); return false; } const Milliseconds connectTimeoutMillis(static_cast<int64_t>( _timeout > 0 ? std::min(kMaxConnectTimeoutMS, (_timeout * 1000)) : kMaxConnectTimeoutMS)); const Date_t expiration = Date_t::now() + connectTimeoutMillis; bool connectSucceeded = ::connect(_fd, _remote.raw(), _remote.addressSize) == 0; if (!connectSucceeded) { #ifdef _WIN32 if (WSAGetLastError() != WSAEWOULDBLOCK) { networkWarnWithDescription(*this, "connect"); return false; } #else if (errno != EINTR && errno != EINPROGRESS) { networkWarnWithDescription(*this, "connect"); return false; } #endif pollfd pfd; pfd.fd = _fd; pfd.events = POLLOUT; while (true) { const auto timeout = std::max(Milliseconds(0), expiration - Date_t::now()); int pollReturn = socketPoll(&pfd, 1, timeout.count()); #ifdef _WIN32 if (pollReturn == SOCKET_ERROR) { networkWarnWithDescription(*this, "poll"); return false; } #else if (pollReturn == -1) { if (errno != EINTR) { networkWarnWithDescription(*this, "poll"); return false; } // EINTR in poll, try again continue; } #endif // No activity for the full duration of the timeout. if (pollReturn == 0) { warning() << "Failed to connect to " << _remote.getAddr() << ":" << _remote.getPort() << " after " << connectTimeoutMillis << " milliseconds, giving up."; return false; } // We had a result, see if there's an error on the socket. int optVal; socklen_t optLen = sizeof(optVal); if (::getsockopt( _fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&optVal), &optLen) == -1) { networkWarnWithDescription(*this, "getsockopt"); return false; } if (optVal != 0) { networkWarnWithDescription(*this, "checking socket for error after poll", optVal); return false; } // We had activity and we don't have errors on the socket, we're connected. break; } } if (!setBlock(_fd, true)) { networkWarnWithDescription(*this, "could not set socket to blocking mode"); return false; } if (_timeout > 0) { setTimeout(_timeout); } if (remote.getType() != AF_UNIX) disableNagle(_fd); #ifdef SO_NOSIGPIPE // ignore SIGPIPE signals on osx, to avoid process exit const int one = 1; setsockopt(_fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int)); #endif _local = getLocalAddrForBoundSocketFd(_fd); _fdCreationMicroSec = curTimeMicros64(); _awaitingHandshake = false; return true; }