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 "TcpServer.h"
9
10#include "logging/Logging.h"
11#include "Acceptor.h"
12#include "EventLoop.h"
13#include "SocketsOps.h"
14
15#include <boost/bind.hpp>
16
17#include <stdio.h>  // snprintf
18
19using namespace muduo;
20
21TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr)
22  : loop_(CHECK_NOTNULL(loop)),
23    name_(listenAddr.toHostPort()),
24    acceptor_(new Acceptor(loop, listenAddr)),
25    started_(false),
26    nextConnId_(1)
27{
28  acceptor_->setNewConnectionCallback(
29      boost::bind(&TcpServer::newConnection, this, _1, _2));
30}
31
32TcpServer::~TcpServer()
33{
34}
35
36void TcpServer::start()
37{
38  if (!started_)
39  {
40    started_ = true;
41  }
42
43  if (!acceptor_->listenning())
44  {
45    loop_->runInLoop(
46        boost::bind(&Acceptor::listen, get_pointer(acceptor_)));
47  }
48}
49
50void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
51{
52  loop_->assertInLoopThread();
53  char buf[32];
54  snprintf(buf, sizeof buf, "#%d", nextConnId_);
55  ++nextConnId_;
56  std::string connName = name_ + buf;
57
58  LOG_INFO << "TcpServer::newConnection [" << name_
59           << "] - new connection [" << connName
60           << "] from " << peerAddr.toHostPort();
61  InetAddress localAddr(sockets::getLocalAddr(sockfd));
62  // FIXME poll with zero timeout to double confirm the new connection
63  TcpConnectionPtr conn(
64      new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr));
65  connections_[connName] = conn;
66  conn->setConnectionCallback(connectionCallback_);
67  conn->setMessageCallback(messageCallback_);
68  conn->setWriteCompleteCallback(writeCompleteCallback_);
69  conn->setCloseCallback(
70      boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe
71  conn->connectEstablished();
72}
73
74void TcpServer::removeConnection(const TcpConnectionPtr& conn)
75{
76  loop_->assertInLoopThread();
77  LOG_INFO << "TcpServer::removeConnection [" << name_
78           << "] - connection " << conn->name();
79  size_t n = connections_.erase(conn->name());
80  assert(n == 1); (void)n;
81  loop_->queueInLoop(
82      boost::bind(&TcpConnection::connectDestroyed, conn));
83}
84
85