1// excerpts from http://code.google.com/p/muduo/ 2// 3// Use of this source code is governed by a BSD-style license 4// that can be found in the License file. 5// 6// Author: Shuo Chen (chenshuo at chenshuo dot com) 7 8#include "TcpClient.h" 9 10#include "Connector.h" 11#include "EventLoop.h" 12#include "SocketsOps.h" 13 14#include "logging/Logging.h" 15 16#include <boost/bind.hpp> 17 18#include <stdio.h> // snprintf 19 20using namespace muduo; 21 22// TcpClient::TcpClient(EventLoop* loop) 23// : loop_(loop) 24// { 25// } 26 27// TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port) 28// : loop_(CHECK_NOTNULL(loop)), 29// serverAddr_(host, port) 30// { 31// } 32 33namespace muduo 34{ 35namespace detail 36{ 37 38void removeConnection(EventLoop* loop, const TcpConnectionPtr& conn) 39{ 40 loop->queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn)); 41} 42 43void removeConnector(const ConnectorPtr& connector) 44{ 45 //connector-> 46} 47 48} 49} 50 51TcpClient::TcpClient(EventLoop* loop, 52 const InetAddress& serverAddr) 53 : loop_(CHECK_NOTNULL(loop)), 54 connector_(new Connector(loop, serverAddr)), 55 retry_(false), 56 connect_(true), 57 nextConnId_(1) 58{ 59 connector_->setNewConnectionCallback( 60 boost::bind(&TcpClient::newConnection, this, _1)); 61 // FIXME setConnectFailedCallback 62 LOG_INFO << "TcpClient::TcpClient[" << this 63 << "] - connector " << get_pointer(connector_); 64} 65 66TcpClient::~TcpClient() 67{ 68 LOG_INFO << "TcpClient::~TcpClient[" << this 69 << "] - connector " << get_pointer(connector_); 70 TcpConnectionPtr conn; 71 { 72 MutexLockGuard lock(mutex_); 73 conn = connection_; 74 } 75 if (conn) 76 { 77 // FIXME: not 100% safe, if we are in different thread 78 CloseCallback cb = boost::bind(&detail::removeConnection, loop_, _1); 79 loop_->runInLoop( 80 boost::bind(&TcpConnection::setCloseCallback, conn, cb)); 81 } 82 else 83 { 84 connector_->stop(); 85 // FIXME: HACK 86 loop_->runAfter(1, boost::bind(&detail::removeConnector, connector_)); 87 } 88} 89 90void TcpClient::connect() 91{ 92 // FIXME: check state 93 LOG_INFO << "TcpClient::connect[" << this << "] - connecting to " 94 << connector_->serverAddress().toHostPort(); 95 connect_ = true; 96 connector_->start(); 97} 98 99void TcpClient::disconnect() 100{ 101 connect_ = false; 102 103 { 104 MutexLockGuard lock(mutex_); 105 if (connection_) 106 { 107 connection_->shutdown(); 108 } 109 } 110} 111 112void TcpClient::stop() 113{ 114 connect_ = false; 115 connector_->stop(); 116} 117 118void TcpClient::newConnection(int sockfd) 119{ 120 loop_->assertInLoopThread(); 121 InetAddress peerAddr(sockets::getPeerAddr(sockfd)); 122 char buf[32]; 123 snprintf(buf, sizeof buf, ":%s#%d", peerAddr.toHostPort().c_str(), nextConnId_); 124 ++nextConnId_; 125 string connName = buf; 126 127 InetAddress localAddr(sockets::getLocalAddr(sockfd)); 128 // FIXME poll with zero timeout to double confirm the new connection 129 // FIXME use make_shared if necessary 130 TcpConnectionPtr conn(new TcpConnection(loop_, 131 connName, 132 sockfd, 133 localAddr, 134 peerAddr)); 135 136 conn->setConnectionCallback(connectionCallback_); 137 conn->setMessageCallback(messageCallback_); 138 conn->setWriteCompleteCallback(writeCompleteCallback_); 139 conn->setCloseCallback( 140 boost::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe 141 { 142 MutexLockGuard lock(mutex_); 143 connection_ = conn; 144 } 145 conn->connectEstablished(); 146} 147 148void TcpClient::removeConnection(const TcpConnectionPtr& conn) 149{ 150 loop_->assertInLoopThread(); 151 assert(loop_ == conn->getLoop()); 152 153 { 154 MutexLockGuard lock(mutex_); 155 assert(connection_ == conn); 156 connection_.reset(); 157 } 158 159 loop_->queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn)); 160 if (retry_ && connect_) 161 { 162 LOG_INFO << "TcpClient::connect[" << this << "] - Reconnecting to " 163 << connector_->serverAddress().toHostPort(); 164 connector_->restart(); 165 } 166} 167 168