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