Advertisement
Guest User

Untitled

a guest
Mar 13th, 2017
203
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.53 KB | None | 0 0
  1. void AsyncSocket::connect(ConnectCallback* callback,
  2.                            const folly::SocketAddress& address,
  3.                            int timeout,
  4.                            const OptionMap &options,
  5.                            const folly::SocketAddress& bindAddr) noexcept {
  6.   DestructorGuard dg(this);
  7.   assert(eventBase_->isInEventBaseThread());
  8.  
  9.   addr_ = address;
  10.  
  11.   // Make sure we're in the uninitialized state
  12.   if (state_ != StateEnum::UNINIT) {
  13.     return invalidState(callback);
  14.   }
  15.  
  16.   connectTimeout_ = std::chrono::milliseconds(timeout);
  17.   connectStartTime_ = std::chrono::steady_clock::now();
  18.   // Make connect end time at least >= connectStartTime.
  19.   connectEndTime_ = connectStartTime_;
  20.  
  21.   assert(fd_ == -1);
  22.   state_ = StateEnum::CONNECTING;
  23.   connectCallback_ = callback;
  24.  
  25.   sockaddr_storage addrStorage;
  26.   sockaddr* saddr = reinterpret_cast<sockaddr*>(&addrStorage);
  27.  
  28.   try {
  29.     // Create the socket
  30.     // Technically the first parameter should actually be a protocol family
  31.     // constant (PF_xxx) rather than an address family (AF_xxx), but the
  32.     // distinction is mainly just historical.  In pretty much all
  33.     // implementations the PF_foo and AF_foo constants are identical.
  34.     fd_ = fsp::socket(address.getFamily(), SOCK_STREAM, 0);
  35.     if (fd_ < 0) {
  36.       auto errnoCopy = errno;
  37.       throw AsyncSocketException(
  38.           AsyncSocketException::INTERNAL_ERROR,
  39.           withAddr("failed to create socket"),
  40.           errnoCopy);
  41.     }
  42.     if (shutdownSocketSet_) {
  43.       shutdownSocketSet_->add(fd_);
  44.     }
  45.     ioHandler_.changeHandlerFD(fd_);
  46.  
  47.     setCloseOnExec();
  48.  
  49.     // Put the socket in non-blocking mode
  50.     int flags = fcntl(fd_, F_GETFL, 0);
  51.     if (flags == -1) {
  52.       auto errnoCopy = errno;
  53.       throw AsyncSocketException(
  54.           AsyncSocketException::INTERNAL_ERROR,
  55.           withAddr("failed to get socket flags"),
  56.           errnoCopy);
  57.     }
  58.     int rv = fcntl(fd_, F_SETFL, flags | O_NONBLOCK);
  59.     if (rv == -1) {
  60.       auto errnoCopy = errno;
  61.       throw AsyncSocketException(
  62.           AsyncSocketException::INTERNAL_ERROR,
  63.           withAddr("failed to put socket in non-blocking mode"),
  64.           errnoCopy);
  65.     }
  66.  
  67. #if !defined(MSG_NOSIGNAL) && defined(F_SETNOSIGPIPE)
  68.     // iOS and OS X don't support MSG_NOSIGNAL; set F_SETNOSIGPIPE instead
  69.     rv = fcntl(fd_, F_SETNOSIGPIPE, 1);
  70.     if (rv == -1) {
  71.       auto errnoCopy = errno;
  72.       throw AsyncSocketException(
  73.           AsyncSocketException::INTERNAL_ERROR,
  74.           "failed to enable F_SETNOSIGPIPE on socket",
  75.           errnoCopy);
  76.     }
  77. #endif
  78.  
  79.     // By default, turn on TCP_NODELAY
  80.     // If setNoDelay() fails, we continue anyway; this isn't a fatal error.
  81.     // setNoDelay() will log an error message if it fails.
  82.     if (address.getFamily() != AF_UNIX) {
  83.       (void)setNoDelay(true);
  84.     }
  85.  
  86.     VLOG(5) << "AsyncSocket::connect(this=" << this << ", evb=" << eventBase_
  87.             << ", fd=" << fd_ << ", host=" << address.describe().c_str();
  88.  
  89.     // bind the socket
  90.     if (bindAddr != anyAddress()) {
  91.       int one = 1;
  92.       if (setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
  93.         auto errnoCopy = errno;
  94.         doClose();
  95.         throw AsyncSocketException(
  96.             AsyncSocketException::NOT_OPEN,
  97.             "failed to setsockopt prior to bind on " + bindAddr.describe(),
  98.             errnoCopy);
  99.       }
  100.  
  101.       bindAddr.getAddress(&addrStorage);
  102.  
  103.       if (bind(fd_, saddr, bindAddr.getActualSize()) != 0) {
  104.         auto errnoCopy = errno;
  105.         doClose();
  106.         throw AsyncSocketException(
  107.             AsyncSocketException::NOT_OPEN,
  108.             "failed to bind to async socket: " + bindAddr.describe(),
  109.             errnoCopy);
  110.       }
  111.     }
  112.  
  113.     // Apply the additional options if any.
  114.     for (const auto& opt: options) {
  115.       rv = opt.first.apply(fd_, opt.second);
  116.       if (rv != 0) {
  117.         auto errnoCopy = errno;
  118.         throw AsyncSocketException(
  119.             AsyncSocketException::INTERNAL_ERROR,
  120.             withAddr("failed to set socket option"),
  121.             errnoCopy);
  122.       }
  123.     }
  124.  
  125.     // Perform the connect()
  126.     address.getAddress(&addrStorage);
  127.  
  128.     if (tfoEnabled_) {
  129.       state_ = StateEnum::FAST_OPEN;
  130.       tfoAttempted_ = true;
  131.     } else {
  132.       if (socketConnect(saddr, addr_.getActualSize()) < 0) {
  133.         return;
  134.       }
  135.     }
  136.  
  137.     // If we're still here the connect() succeeded immediately.
  138.     // Fall through to call the callback outside of this try...catch block
  139.   } catch (const AsyncSocketException& ex) {
  140.     return failConnect(__func__, ex);
  141.   } catch (const std::exception& ex) {
  142.     // shouldn't happen, but handle it just in case
  143.     VLOG(4) << "AsyncSocket::connect(this=" << this << ", fd=" << fd_
  144.                << "): unexpected " << typeid(ex).name() << " exception: "
  145.                << ex.what();
  146.     AsyncSocketException tex(AsyncSocketException::INTERNAL_ERROR,
  147.                             withAddr(string("unexpected exception: ") +
  148.                                      ex.what()));
  149.     return failConnect(__func__, tex);
  150.   }
  151.  
  152.   // The connection succeeded immediately
  153.   // The read callback may not have been set yet, and no writes may be pending
  154.   // yet, so we don't have to register for any events at the moment.
  155.   VLOG(8) << "AsyncSocket::connect succeeded immediately; this=" << this;
  156.   assert(readCallback_ == nullptr);
  157.   assert(writeReqHead_ == nullptr);
  158.   if (state_ != StateEnum::FAST_OPEN) {
  159.     state_ = StateEnum::ESTABLISHED;
  160.   }
  161.   invokeConnectSuccess();
  162. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement