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 "TcpConnection.h"
9
10#include "logging/Logging.h"
11#include "Channel.h"
12#include "EventLoop.h"
13#include "Socket.h"
14#include "SocketsOps.h"
15
16#include <boost/bind.hpp>
17
18#include <errno.h>
19#include <stdio.h>
20
21using namespace muduo;
22
23TcpConnection::TcpConnection(EventLoop* loop,
24                             const std::string& nameArg,
25                             int sockfd,
26                             const InetAddress& localAddr,
27                             const InetAddress& peerAddr)
28  : loop_(CHECK_NOTNULL(loop)),
29    name_(nameArg),
30    state_(kConnecting),
31    socket_(new Socket(sockfd)),
32    channel_(new Channel(loop, sockfd)),
33    localAddr_(localAddr),
34    peerAddr_(peerAddr)
35{
36  LOG_DEBUG << "TcpConnection::ctor[" <<  name_ << "] at " << this
37            << " fd=" << sockfd;
38  channel_->setReadCallback(
39      boost::bind(&TcpConnection::handleRead, this));
40  channel_->setWriteCallback(
41      boost::bind(&TcpConnection::handleWrite, this));
42  channel_->setCloseCallback(
43      boost::bind(&TcpConnection::handleClose, this));
44  channel_->setErrorCallback(
45      boost::bind(&TcpConnection::handleError, this));
46}
47
48TcpConnection::~TcpConnection()
49{
50  LOG_DEBUG << "TcpConnection::dtor[" <<  name_ << "] at " << this
51            << " fd=" << channel_->fd();
52}
53
54void TcpConnection::connectEstablished()
55{
56  loop_->assertInLoopThread();
57  assert(state_ == kConnecting);
58  setState(kConnected);
59  channel_->enableReading();
60  connectionCallback_(shared_from_this());
61}
62
63void TcpConnection::connectDestroyed()
64{
65  loop_->assertInLoopThread();
66  assert(state_ == kConnected);
67  setState(kDisconnected);
68  channel_->disableAll();
69  connectionCallback_(shared_from_this());
70
71  loop_->removeChannel(get_pointer(channel_));
72}
73
74void TcpConnection::handleRead()
75{
76  char buf[65536];
77  ssize_t n = ::read(channel_->fd(), buf, sizeof buf);
78  if (n > 0) {
79    messageCallback_(shared_from_this(), buf, n);
80  } else if (n == 0) {
81    handleClose();
82  } else {
83    handleError();
84  }
85}
86
87void TcpConnection::handleWrite()
88{
89}
90
91void TcpConnection::handleClose()
92{
93  loop_->assertInLoopThread();
94  LOG_TRACE << "TcpConnection::handleClose state = " << state_;
95  assert(state_ == kConnected);
96  // we don't close fd, leave it to dtor, so we can find leaks easily.
97  channel_->disableAll();
98  // must be the last line
99  closeCallback_(shared_from_this());
100}
101
102void TcpConnection::handleError()
103{
104  int err = sockets::getSocketError(channel_->fd());
105  LOG_ERROR << "TcpConnection::handleError [" << name_
106            << "] - SO_ERROR = " << err << " " << strerror_tl(err);
107}
108