Connector.cc revision f4e8e3d3
104e5c324SShuo Chen// excerpts from http://code.google.com/p/muduo/
204e5c324SShuo Chen//
304e5c324SShuo Chen// Use of this source code is governed by a BSD-style license
404e5c324SShuo Chen// that can be found in the License file.
504e5c324SShuo Chen//
604e5c324SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
704e5c324SShuo Chen
804e5c324SShuo Chen#include "Connector.h"
904e5c324SShuo Chen
1004e5c324SShuo Chen#include "Channel.h"
1104e5c324SShuo Chen#include "EventLoop.h"
1204e5c324SShuo Chen#include "SocketsOps.h"
1304e5c324SShuo Chen
1404e5c324SShuo Chen#include "logging/Logging.h"
1504e5c324SShuo Chen
1604e5c324SShuo Chen#include <boost/bind.hpp>
1704e5c324SShuo Chen
1804e5c324SShuo Chen#include <errno.h>
1904e5c324SShuo Chen
2004e5c324SShuo Chenusing namespace muduo;
2104e5c324SShuo Chen
2204e5c324SShuo Chenconst int Connector::kMaxRetryDelayMs;
2304e5c324SShuo Chen
2404e5c324SShuo ChenConnector::Connector(EventLoop* loop, const InetAddress& serverAddr)
2504e5c324SShuo Chen  : loop_(loop),
2604e5c324SShuo Chen    serverAddr_(serverAddr),
2704e5c324SShuo Chen    connect_(false),
2804e5c324SShuo Chen    state_(kDisconnected),
2904e5c324SShuo Chen    retryDelayMs_(kInitRetryDelayMs)
3004e5c324SShuo Chen{
3104e5c324SShuo Chen  LOG_DEBUG << "ctor[" << this << "]";
3204e5c324SShuo Chen}
3304e5c324SShuo Chen
3404e5c324SShuo ChenConnector::~Connector()
3504e5c324SShuo Chen{
3604e5c324SShuo Chen  LOG_DEBUG << "dtor[" << this << "]";
37f4e8e3d3SShuo Chen  loop_->cancel(timerId_);
3804e5c324SShuo Chen  assert(!channel_);
3904e5c324SShuo Chen}
4004e5c324SShuo Chen
4104e5c324SShuo Chenvoid Connector::start()
4204e5c324SShuo Chen{
4304e5c324SShuo Chen  connect_ = true;
4404e5c324SShuo Chen  loop_->runInLoop(boost::bind(&Connector::startInLoop, this)); // FIXME: unsafe
4504e5c324SShuo Chen}
4604e5c324SShuo Chen
4704e5c324SShuo Chenvoid Connector::startInLoop()
4804e5c324SShuo Chen{
4904e5c324SShuo Chen  loop_->assertInLoopThread();
5004e5c324SShuo Chen  assert(state_ == kDisconnected);
5104e5c324SShuo Chen  if (connect_)
5204e5c324SShuo Chen  {
5304e5c324SShuo Chen    connect();
5404e5c324SShuo Chen  }
5504e5c324SShuo Chen  else
5604e5c324SShuo Chen  {
5704e5c324SShuo Chen    LOG_DEBUG << "do not connect";
5804e5c324SShuo Chen  }
5904e5c324SShuo Chen}
6004e5c324SShuo Chen
6104e5c324SShuo Chenvoid Connector::connect()
6204e5c324SShuo Chen{
6304e5c324SShuo Chen  int sockfd = sockets::createNonblockingOrDie();
6404e5c324SShuo Chen  int ret = sockets::connect(sockfd, serverAddr_.getSockAddrInet());
6504e5c324SShuo Chen  int savedErrno = (ret == 0) ? 0 : errno;
6604e5c324SShuo Chen  switch (savedErrno)
6704e5c324SShuo Chen  {
6804e5c324SShuo Chen    case 0:
6904e5c324SShuo Chen    case EINPROGRESS:
7004e5c324SShuo Chen    case EINTR:
7104e5c324SShuo Chen    case EISCONN:
7204e5c324SShuo Chen      connecting(sockfd);
7304e5c324SShuo Chen      break;
7404e5c324SShuo Chen
7504e5c324SShuo Chen    case EAGAIN:
7604e5c324SShuo Chen    case EADDRINUSE:
7704e5c324SShuo Chen    case EADDRNOTAVAIL:
7804e5c324SShuo Chen    case ECONNREFUSED:
7904e5c324SShuo Chen    case ENETUNREACH:
8004e5c324SShuo Chen      retry(sockfd);
8104e5c324SShuo Chen      break;
8204e5c324SShuo Chen
8304e5c324SShuo Chen    case EACCES:
8404e5c324SShuo Chen    case EPERM:
8504e5c324SShuo Chen    case EAFNOSUPPORT:
8604e5c324SShuo Chen    case EALREADY:
8704e5c324SShuo Chen    case EBADF:
8804e5c324SShuo Chen    case EFAULT:
8904e5c324SShuo Chen    case ENOTSOCK:
9004e5c324SShuo Chen      LOG_SYSERR << "connect error in Connector::startInLoop " << savedErrno;
9104e5c324SShuo Chen      sockets::close(sockfd);
9204e5c324SShuo Chen      break;
9304e5c324SShuo Chen
9404e5c324SShuo Chen    default:
9504e5c324SShuo Chen      LOG_SYSERR << "Unexpected error in Connector::startInLoop " << savedErrno;
9604e5c324SShuo Chen      sockets::close(sockfd);
9704e5c324SShuo Chen      // connectErrorCallback_();
9804e5c324SShuo Chen      break;
9904e5c324SShuo Chen  }
10004e5c324SShuo Chen}
10104e5c324SShuo Chen
10204e5c324SShuo Chenvoid Connector::restart()
10304e5c324SShuo Chen{
10404e5c324SShuo Chen  loop_->assertInLoopThread();
10504e5c324SShuo Chen  setState(kDisconnected);
10604e5c324SShuo Chen  retryDelayMs_ = kInitRetryDelayMs;
10704e5c324SShuo Chen  connect_ = true;
10804e5c324SShuo Chen  startInLoop();
10904e5c324SShuo Chen}
11004e5c324SShuo Chen
11104e5c324SShuo Chenvoid Connector::stop()
11204e5c324SShuo Chen{
11304e5c324SShuo Chen  connect_ = false;
11404e5c324SShuo Chen  // FIXME: cancel timer
11504e5c324SShuo Chen}
11604e5c324SShuo Chen
11704e5c324SShuo Chenvoid Connector::connecting(int sockfd)
11804e5c324SShuo Chen{
11904e5c324SShuo Chen  setState(kConnecting);
12004e5c324SShuo Chen  assert(!channel_);
12104e5c324SShuo Chen  channel_.reset(new Channel(loop_, sockfd));
12204e5c324SShuo Chen  channel_->setWriteCallback(
12304e5c324SShuo Chen      boost::bind(&Connector::handleWrite, this)); // FIXME: unsafe
12404e5c324SShuo Chen  channel_->setErrorCallback(
12504e5c324SShuo Chen      boost::bind(&Connector::handleError, this)); // FIXME: unsafe
12604e5c324SShuo Chen
12704e5c324SShuo Chen  // channel_->tie(shared_from_this()); is not working,
12804e5c324SShuo Chen  // as channel_ is not managed by shared_ptr
12904e5c324SShuo Chen  channel_->enableWriting();
13004e5c324SShuo Chen}
13104e5c324SShuo Chen
13204e5c324SShuo Chenint Connector::removeAndResetChannel()
13304e5c324SShuo Chen{
13404e5c324SShuo Chen  channel_->disableAll();
13504e5c324SShuo Chen  loop_->removeChannel(get_pointer(channel_));
13604e5c324SShuo Chen  int sockfd = channel_->fd();
13704e5c324SShuo Chen  // Can't reset channel_ here, because we are inside Channel::handleEvent
13804e5c324SShuo Chen  loop_->queueInLoop(boost::bind(&Connector::resetChannel, this)); // FIXME: unsafe
13904e5c324SShuo Chen  return sockfd;
14004e5c324SShuo Chen}
14104e5c324SShuo Chen
14204e5c324SShuo Chenvoid Connector::resetChannel()
14304e5c324SShuo Chen{
14404e5c324SShuo Chen  channel_.reset();
14504e5c324SShuo Chen}
14604e5c324SShuo Chen
14704e5c324SShuo Chenvoid Connector::handleWrite()
14804e5c324SShuo Chen{
14904e5c324SShuo Chen  LOG_TRACE << "Connector::handleWrite " << state_;
15004e5c324SShuo Chen
15104e5c324SShuo Chen  if (state_ == kConnecting)
15204e5c324SShuo Chen  {
15304e5c324SShuo Chen    int sockfd = removeAndResetChannel();
15404e5c324SShuo Chen    int err = sockets::getSocketError(sockfd);
15504e5c324SShuo Chen    if (err)
15604e5c324SShuo Chen    {
15704e5c324SShuo Chen      LOG_WARN << "Connector::handleWrite - SO_ERROR = "
15804e5c324SShuo Chen               << err << " " << strerror_tl(err);
15904e5c324SShuo Chen      retry(sockfd);
16004e5c324SShuo Chen    }
16104e5c324SShuo Chen    else if (sockets::isSelfConnect(sockfd))
16204e5c324SShuo Chen    {
16304e5c324SShuo Chen      LOG_WARN << "Connector::handleWrite - Self connect";
16404e5c324SShuo Chen      retry(sockfd);
16504e5c324SShuo Chen    }
16604e5c324SShuo Chen    else
16704e5c324SShuo Chen    {
16804e5c324SShuo Chen      setState(kConnected);
16904e5c324SShuo Chen      if (connect_)
17004e5c324SShuo Chen      {
17104e5c324SShuo Chen        newConnectionCallback_(sockfd);
17204e5c324SShuo Chen      }
17304e5c324SShuo Chen      else
17404e5c324SShuo Chen      {
17504e5c324SShuo Chen        sockets::close(sockfd);
17604e5c324SShuo Chen      }
17704e5c324SShuo Chen    }
17804e5c324SShuo Chen  }
17904e5c324SShuo Chen  else
18004e5c324SShuo Chen  {
18104e5c324SShuo Chen    // what happened?
18204e5c324SShuo Chen    assert(state_ == kDisconnected);
18304e5c324SShuo Chen  }
18404e5c324SShuo Chen}
18504e5c324SShuo Chen
18604e5c324SShuo Chenvoid Connector::handleError()
18704e5c324SShuo Chen{
18804e5c324SShuo Chen  LOG_ERROR << "Connector::handleError";
18904e5c324SShuo Chen  assert(state_ == kConnecting);
19004e5c324SShuo Chen
19104e5c324SShuo Chen  int sockfd = removeAndResetChannel();
19204e5c324SShuo Chen  int err = sockets::getSocketError(sockfd);
19304e5c324SShuo Chen  LOG_TRACE << "SO_ERROR = " << err << " " << strerror_tl(err);
19404e5c324SShuo Chen  retry(sockfd);
19504e5c324SShuo Chen}
19604e5c324SShuo Chen
19704e5c324SShuo Chenvoid Connector::retry(int sockfd)
19804e5c324SShuo Chen{
19904e5c324SShuo Chen  sockets::close(sockfd);
20004e5c324SShuo Chen  setState(kDisconnected);
20104e5c324SShuo Chen  if (connect_)
20204e5c324SShuo Chen  {
203f4e8e3d3SShuo Chen    LOG_INFO << "Connector::retry - Retry connecting to "
204f4e8e3d3SShuo Chen             << serverAddr_.toHostPort() << " in "
205f4e8e3d3SShuo Chen             << retryDelayMs_ << " milliseconds. ";
206f4e8e3d3SShuo Chen    timerId_ = loop_->runAfter(retryDelayMs_/1000.0,  // FIXME: unsafe
207f4e8e3d3SShuo Chen                               boost::bind(&Connector::startInLoop, this));
20804e5c324SShuo Chen    retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs);
20904e5c324SShuo Chen  }
21004e5c324SShuo Chen  else
21104e5c324SShuo Chen  {
21204e5c324SShuo Chen    LOG_DEBUG << "do not connect";
21304e5c324SShuo Chen  }
21404e5c324SShuo Chen}
21504e5c324SShuo Chen
216