Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- void AsyncSocket::connect(ConnectCallback* callback,
- const folly::SocketAddress& address,
- int timeout,
- const OptionMap &options,
- const folly::SocketAddress& bindAddr) noexcept {
- DestructorGuard dg(this);
- assert(eventBase_->isInEventBaseThread());
- addr_ = address;
- // Make sure we're in the uninitialized state
- if (state_ != StateEnum::UNINIT) {
- return invalidState(callback);
- }
- connectTimeout_ = std::chrono::milliseconds(timeout);
- connectStartTime_ = std::chrono::steady_clock::now();
- // Make connect end time at least >= connectStartTime.
- connectEndTime_ = connectStartTime_;
- assert(fd_ == -1);
- state_ = StateEnum::CONNECTING;
- connectCallback_ = callback;
- sockaddr_storage addrStorage;
- sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage);
- try {
- // Create the socket
- // Technically the first parameter should actually be a protocol family
- // constant (PF_xxx) rather than an address family (AF_xxx), but the
- // distinction is mainly just historical. In pretty much all
- // implementations the PF_foo and AF_foo constants are identical.
- fd_ = fsp::socket(address.getFamily(), SOCK_STREAM, 0);
- if (fd_ < 0) {
- auto errnoCopy = errno;
- throw AsyncSocketException(
- AsyncSocketException::INTERNAL_ERROR,
- withAddr("failed to create socket"),
- errnoCopy);
- }
- if (shutdownSocketSet_) {
- shutdownSocketSet_->add(fd_);
- }
- ioHandler_.changeHandlerFD(fd_);
- setCloseOnExec();
- // Put the socket in non-blocking mode
- int flags = fcntl(fd_, F_GETFL, 0);
- if (flags == -1) {
- auto errnoCopy = errno;
- throw AsyncSocketException(
- AsyncSocketException::INTERNAL_ERROR,
- withAddr("failed to get socket flags"),
- errnoCopy);
- }
- int rv = fcntl(fd_, F_SETFL, flags | O_NONBLOCK);
- if (rv == -1) {
- auto errnoCopy = errno;
- throw AsyncSocketException(
- AsyncSocketException::INTERNAL_ERROR,
- withAddr("failed to put socket in non-blocking mode"),
- errnoCopy);
- }
- #if !defined(MSG_NOSIGNAL) && defined(F_SETNOSIGPIPE)
- // iOS and OS X don't support MSG_NOSIGNAL; set F_SETNOSIGPIPE instead
- rv = fcntl(fd_, F_SETNOSIGPIPE, 1);
- if (rv == -1) {
- auto errnoCopy = errno;
- throw AsyncSocketException(
- AsyncSocketException::INTERNAL_ERROR,
- "failed to enable F_SETNOSIGPIPE on socket",
- errnoCopy);
- }
- #endif
- // By default, turn on TCP_NODELAY
- // If setNoDelay() fails, we continue anyway; this isn't a fatal error.
- // setNoDelay() will log an error message if it fails.
- if (address.getFamily() != AF_UNIX) {
- (void)setNoDelay(true);
- }
- VLOG(5) << "AsyncSocket::connect(this=" << this << ", evb=" << eventBase_
- << ", fd=" << fd_ << ", host=" << address.describe().c_str();
- // bind the socket
- if (bindAddr != anyAddress()) {
- int one = 1;
- if (setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
- auto errnoCopy = errno;
- doClose();
- throw AsyncSocketException(
- AsyncSocketException::NOT_OPEN,
- "failed to setsockopt prior to bind on " + bindAddr.describe(),
- errnoCopy);
- }
- bindAddr.getAddress(&addrStorage);
- if (bind(fd_, saddr, bindAddr.getActualSize()) != 0) {
- auto errnoCopy = errno;
- doClose();
- throw AsyncSocketException(
- AsyncSocketException::NOT_OPEN,
- "failed to bind to async socket: " + bindAddr.describe(),
- errnoCopy);
- }
- }
- // Apply the additional options if any.
- for (const auto& opt: options) {
- rv = opt.first.apply(fd_, opt.second);
- if (rv != 0) {
- auto errnoCopy = errno;
- throw AsyncSocketException(
- AsyncSocketException::INTERNAL_ERROR,
- withAddr("failed to set socket option"),
- errnoCopy);
- }
- }
- // Perform the connect()
- address.getAddress(&addrStorage);
- if (tfoEnabled_) {
- state_ = StateEnum::FAST_OPEN;
- tfoAttempted_ = true;
- } else {
- if (socketConnect(saddr, addr_.getActualSize()) < 0) {
- return;
- }
- }
- // If we're still here the connect() succeeded immediately.
- // Fall through to call the callback outside of this try...catch block
- } catch (const AsyncSocketException& ex) {
- return failConnect(__func__, ex);
- } catch (const std::exception& ex) {
- // shouldn't happen, but handle it just in case
- VLOG(4) << "AsyncSocket::connect(this=" << this << ", fd=" << fd_
- << "): unexpected " << typeid(ex).name() << " exception: "
- << ex.what();
- AsyncSocketException tex(AsyncSocketException::INTERNAL_ERROR,
- withAddr(string("unexpected exception: ") +
- ex.what()));
- return failConnect(__func__, tex);
- }
- // The connection succeeded immediately
- // The read callback may not have been set yet, and no writes may be pending
- // yet, so we don't have to register for any events at the moment.
- VLOG(8) << "AsyncSocket::connect succeeded immediately; this=" << this;
- assert(readCallback_ == nullptr);
- assert(writeReqHead_ == nullptr);
- if (state_ != StateEnum::FAST_OPEN) {
- state_ = StateEnum::ESTABLISHED;
- }
- invokeConnectSuccess();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement