1e254a845SShuo Chen// excerpts from http://code.google.com/p/muduo/
2e254a845SShuo Chen//
3e254a845SShuo Chen// Use of this source code is governed by a BSD-style license
4e254a845SShuo Chen// that can be found in the License file.
5e254a845SShuo Chen//
6e254a845SShuo Chen// Author: Shuo Chen (chenshuo at chenshuo dot com)
7e254a845SShuo Chen
8e254a845SShuo Chen#include "TcpServer.h"
9e254a845SShuo Chen
10e254a845SShuo Chen#include "logging/Logging.h"
11e254a845SShuo Chen#include "Acceptor.h"
12e254a845SShuo Chen#include "EventLoop.h"
1399dd5949SShuo Chen#include "EventLoopThreadPool.h"
14e254a845SShuo Chen#include "SocketsOps.h"
15e254a845SShuo Chen
16e254a845SShuo Chen#include <boost/bind.hpp>
17e254a845SShuo Chen
18e254a845SShuo Chen#include <stdio.h>  // snprintf
19e254a845SShuo Chen
20e254a845SShuo Chenusing namespace muduo;
21e254a845SShuo Chen
22e254a845SShuo ChenTcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr)
23e254a845SShuo Chen  : loop_(CHECK_NOTNULL(loop)),
24e254a845SShuo Chen    name_(listenAddr.toHostPort()),
25e254a845SShuo Chen    acceptor_(new Acceptor(loop, listenAddr)),
2699dd5949SShuo Chen    threadPool_(new EventLoopThreadPool(loop)),
27e254a845SShuo Chen    started_(false),
28e254a845SShuo Chen    nextConnId_(1)
29e254a845SShuo Chen{
30e254a845SShuo Chen  acceptor_->setNewConnectionCallback(
31e254a845SShuo Chen      boost::bind(&TcpServer::newConnection, this, _1, _2));
32e254a845SShuo Chen}
33e254a845SShuo Chen
34e254a845SShuo ChenTcpServer::~TcpServer()
35e254a845SShuo Chen{
36e254a845SShuo Chen}
37e254a845SShuo Chen
3899dd5949SShuo Chenvoid TcpServer::setThreadNum(int numThreads)
3999dd5949SShuo Chen{
4099dd5949SShuo Chen  assert(0 <= numThreads);
4199dd5949SShuo Chen  threadPool_->setThreadNum(numThreads);
4299dd5949SShuo Chen}
4399dd5949SShuo Chen
44e254a845SShuo Chenvoid TcpServer::start()
45e254a845SShuo Chen{
46e254a845SShuo Chen  if (!started_)
47e254a845SShuo Chen  {
48e254a845SShuo Chen    started_ = true;
4999dd5949SShuo Chen    threadPool_->start();
50e254a845SShuo Chen  }
51e254a845SShuo Chen
52e254a845SShuo Chen  if (!acceptor_->listenning())
53e254a845SShuo Chen  {
54e254a845SShuo Chen    loop_->runInLoop(
55e254a845SShuo Chen        boost::bind(&Acceptor::listen, get_pointer(acceptor_)));
56e254a845SShuo Chen  }
57e254a845SShuo Chen}
58e254a845SShuo Chen
59e254a845SShuo Chenvoid TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
60e254a845SShuo Chen{
61e254a845SShuo Chen  loop_->assertInLoopThread();
62e254a845SShuo Chen  char buf[32];
63e254a845SShuo Chen  snprintf(buf, sizeof buf, "#%d", nextConnId_);
64e254a845SShuo Chen  ++nextConnId_;
65e254a845SShuo Chen  std::string connName = name_ + buf;
66e254a845SShuo Chen
67e254a845SShuo Chen  LOG_INFO << "TcpServer::newConnection [" << name_
68e254a845SShuo Chen           << "] - new connection [" << connName
69e254a845SShuo Chen           << "] from " << peerAddr.toHostPort();
70e254a845SShuo Chen  InetAddress localAddr(sockets::getLocalAddr(sockfd));
71e254a845SShuo Chen  // FIXME poll with zero timeout to double confirm the new connection
7299dd5949SShuo Chen  EventLoop* ioLoop = threadPool_->getNextLoop();
73e254a845SShuo Chen  TcpConnectionPtr conn(
7499dd5949SShuo Chen      new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr));
75e254a845SShuo Chen  connections_[connName] = conn;
76e254a845SShuo Chen  conn->setConnectionCallback(connectionCallback_);
77e254a845SShuo Chen  conn->setMessageCallback(messageCallback_);
78e254a845SShuo Chen  conn->setWriteCompleteCallback(writeCompleteCallback_);
79e254a845SShuo Chen  conn->setCloseCallback(
8099dd5949SShuo Chen      boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe
8199dd5949SShuo Chen  ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));
82e254a845SShuo Chen}
83e254a845SShuo Chen
84e254a845SShuo Chenvoid TcpServer::removeConnection(const TcpConnectionPtr& conn)
85e254a845SShuo Chen{
8699dd5949SShuo Chen  // FIXME: unsafe
8799dd5949SShuo Chen  loop_->runInLoop(boost::bind(&TcpServer::removeConnectionInLoop, this, conn));
8899dd5949SShuo Chen}
8999dd5949SShuo Chen
9099dd5949SShuo Chenvoid TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn)
9199dd5949SShuo Chen{
92e254a845SShuo Chen  loop_->assertInLoopThread();
9399dd5949SShuo Chen  LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_
94e254a845SShuo Chen           << "] - connection " << conn->name();
95e254a845SShuo Chen  size_t n = connections_.erase(conn->name());
96e254a845SShuo Chen  assert(n == 1); (void)n;
9799dd5949SShuo Chen  EventLoop* ioLoop = conn->getLoop();
9899dd5949SShuo Chen  ioLoop->queueInLoop(
99e254a845SShuo Chen      boost::bind(&TcpConnection::connectDestroyed, conn));
100e254a845SShuo Chen}
101e254a845SShuo Chen
102