140161064SShuo Chen// excerpts from http://code.google.com/p/muduo/
240161064SShuo Chen//
340161064SShuo Chen// Use of this source code is governed by a BSD-style license
440161064SShuo Chen// that can be found in the License file.
540161064SShuo Chen//
640161064SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
740161064SShuo Chen
840161064SShuo Chen#include "TcpServer.h"
940161064SShuo Chen
1040161064SShuo Chen#include "logging/Logging.h"
1140161064SShuo Chen#include "Acceptor.h"
1240161064SShuo Chen#include "EventLoop.h"
1340161064SShuo Chen#include "EventLoopThreadPool.h"
1440161064SShuo Chen#include "SocketsOps.h"
1540161064SShuo Chen
1640161064SShuo Chen#include <boost/bind.hpp>
1740161064SShuo Chen
1840161064SShuo Chen#include <stdio.h>  // snprintf
1940161064SShuo Chen
2040161064SShuo Chenusing namespace muduo;
2140161064SShuo Chen
2240161064SShuo ChenTcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr)
2340161064SShuo Chen  : loop_(CHECK_NOTNULL(loop)),
2440161064SShuo Chen    name_(listenAddr.toHostPort()),
2540161064SShuo Chen    acceptor_(new Acceptor(loop, listenAddr)),
2640161064SShuo Chen    threadPool_(new EventLoopThreadPool(loop)),
2740161064SShuo Chen    started_(false),
2840161064SShuo Chen    nextConnId_(1)
2940161064SShuo Chen{
3040161064SShuo Chen  acceptor_->setNewConnectionCallback(
3140161064SShuo Chen      boost::bind(&TcpServer::newConnection, this, _1, _2));
3240161064SShuo Chen}
3340161064SShuo Chen
3440161064SShuo ChenTcpServer::~TcpServer()
3540161064SShuo Chen{
3640161064SShuo Chen}
3740161064SShuo Chen
3840161064SShuo Chenvoid TcpServer::setThreadNum(int numThreads)
3940161064SShuo Chen{
4040161064SShuo Chen  assert(0 <= numThreads);
4140161064SShuo Chen  threadPool_->setThreadNum(numThreads);
4240161064SShuo Chen}
4340161064SShuo Chen
4440161064SShuo Chenvoid TcpServer::start()
4540161064SShuo Chen{
4640161064SShuo Chen  if (!started_)
4740161064SShuo Chen  {
4840161064SShuo Chen    started_ = true;
4940161064SShuo Chen    threadPool_->start();
5040161064SShuo Chen  }
5140161064SShuo Chen
5240161064SShuo Chen  if (!acceptor_->listenning())
5340161064SShuo Chen  {
5440161064SShuo Chen    loop_->runInLoop(
5540161064SShuo Chen        boost::bind(&Acceptor::listen, get_pointer(acceptor_)));
5640161064SShuo Chen  }
5740161064SShuo Chen}
5840161064SShuo Chen
5940161064SShuo Chenvoid TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
6040161064SShuo Chen{
6140161064SShuo Chen  loop_->assertInLoopThread();
6240161064SShuo Chen  char buf[32];
6340161064SShuo Chen  snprintf(buf, sizeof buf, "#%d", nextConnId_);
6440161064SShuo Chen  ++nextConnId_;
6540161064SShuo Chen  std::string connName = name_ + buf;
6640161064SShuo Chen
6740161064SShuo Chen  LOG_INFO << "TcpServer::newConnection [" << name_
6840161064SShuo Chen           << "] - new connection [" << connName
6940161064SShuo Chen           << "] from " << peerAddr.toHostPort();
7040161064SShuo Chen  InetAddress localAddr(sockets::getLocalAddr(sockfd));
7140161064SShuo Chen  // FIXME poll with zero timeout to double confirm the new connection
7240161064SShuo Chen  EventLoop* ioLoop = threadPool_->getNextLoop();
7340161064SShuo Chen  TcpConnectionPtr conn(
7440161064SShuo Chen      new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr));
7540161064SShuo Chen  connections_[connName] = conn;
7640161064SShuo Chen  conn->setConnectionCallback(connectionCallback_);
7740161064SShuo Chen  conn->setMessageCallback(messageCallback_);
7840161064SShuo Chen  conn->setWriteCompleteCallback(writeCompleteCallback_);
7940161064SShuo Chen  conn->setCloseCallback(
8040161064SShuo Chen      boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe
8140161064SShuo Chen  ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));
8240161064SShuo Chen}
8340161064SShuo Chen
8440161064SShuo Chenvoid TcpServer::removeConnection(const TcpConnectionPtr& conn)
8540161064SShuo Chen{
8640161064SShuo Chen  // FIXME: unsafe
8740161064SShuo Chen  loop_->runInLoop(boost::bind(&TcpServer::removeConnectionInLoop, this, conn));
8840161064SShuo Chen}
8940161064SShuo Chen
9040161064SShuo Chenvoid TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn)
9140161064SShuo Chen{
9240161064SShuo Chen  loop_->assertInLoopThread();
9340161064SShuo Chen  LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_
9440161064SShuo Chen           << "] - connection " << conn->name();
9540161064SShuo Chen  size_t n = connections_.erase(conn->name());
9640161064SShuo Chen  assert(n == 1); (void)n;
9740161064SShuo Chen  EventLoop* ioLoop = conn->getLoop();
9840161064SShuo Chen  ioLoop->queueInLoop(
9940161064SShuo Chen      boost::bind(&TcpConnection::connectDestroyed, conn));
10040161064SShuo Chen}
10140161064SShuo Chen
102