12a18e699SShuo Chen// excerpts from http://code.google.com/p/muduo/
22a18e699SShuo Chen//
32a18e699SShuo Chen// Use of this source code is governed by a BSD-style license
42a18e699SShuo Chen// that can be found in the License file.
52a18e699SShuo Chen//
62a18e699SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
72a18e699SShuo Chen
82a18e699SShuo Chen#include "TcpServer.h"
92a18e699SShuo Chen
102a18e699SShuo Chen#include "logging/Logging.h"
112a18e699SShuo Chen#include "Acceptor.h"
122a18e699SShuo Chen#include "EventLoop.h"
132a18e699SShuo Chen#include "SocketsOps.h"
142a18e699SShuo Chen
152a18e699SShuo Chen#include <boost/bind.hpp>
162a18e699SShuo Chen
172a18e699SShuo Chen#include <stdio.h>  // snprintf
182a18e699SShuo Chen
192a18e699SShuo Chenusing namespace muduo;
202a18e699SShuo Chen
212a18e699SShuo ChenTcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr)
222a18e699SShuo Chen  : loop_(CHECK_NOTNULL(loop)),
232a18e699SShuo Chen    name_(listenAddr.toHostPort()),
242a18e699SShuo Chen    acceptor_(new Acceptor(loop, listenAddr)),
252a18e699SShuo Chen    started_(false),
262a18e699SShuo Chen    nextConnId_(1)
272a18e699SShuo Chen{
282a18e699SShuo Chen  acceptor_->setNewConnectionCallback(
292a18e699SShuo Chen      boost::bind(&TcpServer::newConnection, this, _1, _2));
302a18e699SShuo Chen}
312a18e699SShuo Chen
322a18e699SShuo ChenTcpServer::~TcpServer()
332a18e699SShuo Chen{
342a18e699SShuo Chen}
352a18e699SShuo Chen
362a18e699SShuo Chenvoid TcpServer::start()
372a18e699SShuo Chen{
382a18e699SShuo Chen  if (!started_)
392a18e699SShuo Chen  {
402a18e699SShuo Chen    started_ = true;
412a18e699SShuo Chen  }
422a18e699SShuo Chen
432a18e699SShuo Chen  if (!acceptor_->listenning())
442a18e699SShuo Chen  {
452a18e699SShuo Chen    loop_->runInLoop(
462a18e699SShuo Chen        boost::bind(&Acceptor::listen, get_pointer(acceptor_)));
472a18e699SShuo Chen  }
482a18e699SShuo Chen}
492a18e699SShuo Chen
502a18e699SShuo Chenvoid TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
512a18e699SShuo Chen{
522a18e699SShuo Chen  loop_->assertInLoopThread();
532a18e699SShuo Chen  char buf[32];
542a18e699SShuo Chen  snprintf(buf, sizeof buf, "#%d", nextConnId_);
552a18e699SShuo Chen  ++nextConnId_;
562a18e699SShuo Chen  std::string connName = name_ + buf;
572a18e699SShuo Chen
582a18e699SShuo Chen  LOG_INFO << "TcpServer::newConnection [" << name_
592a18e699SShuo Chen           << "] - new connection [" << connName
602a18e699SShuo Chen           << "] from " << peerAddr.toHostPort();
612a18e699SShuo Chen  InetAddress localAddr(sockets::getLocalAddr(sockfd));
622a18e699SShuo Chen  // FIXME poll with zero timeout to double confirm the new connection
632a18e699SShuo Chen  TcpConnectionPtr conn(
642a18e699SShuo Chen      new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr));
652a18e699SShuo Chen  connections_[connName] = conn;
662a18e699SShuo Chen  conn->setConnectionCallback(connectionCallback_);
672a18e699SShuo Chen  conn->setMessageCallback(messageCallback_);
682a18e699SShuo Chen  conn->setCloseCallback(
692a18e699SShuo Chen      boost::bind(&TcpServer::removeConnection, this, _1));
702a18e699SShuo Chen  conn->connectEstablished();
712a18e699SShuo Chen}
722a18e699SShuo Chen
732a18e699SShuo Chenvoid TcpServer::removeConnection(const TcpConnectionPtr& conn)
742a18e699SShuo Chen{
752a18e699SShuo Chen  loop_->assertInLoopThread();
762a18e699SShuo Chen  LOG_INFO << "TcpServer::removeConnection [" << name_
772a18e699SShuo Chen           << "] - connection " << conn->name();
782a18e699SShuo Chen  size_t n = connections_.erase(conn->name());
792a18e699SShuo Chen  assert(n == 1); (void)n;
802a18e699SShuo Chen  loop_->queueInLoop(
812a18e699SShuo Chen      boost::bind(&TcpConnection::connectDestroyed, conn));
822a18e699SShuo Chen}
832a18e699SShuo Chen
84