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 
21 using namespace muduo;
22 
23 TcpConnection::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, _1));
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 
48 TcpConnection::~TcpConnection()
49 {
50   LOG_DEBUG << "TcpConnection::dtor[" <<  name_ << "] at " << this
51             << " fd=" << channel_->fd();
52 }
53 
54 void TcpConnection::connectEstablished()
55 {
56   loop_->assertInLoopThread();
57   assert(state_ == kConnecting);
58   setState(kConnected);
59   channel_->enableReading();
60   connectionCallback_(shared_from_this());
61 }
62 
63 void 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 
74!void TcpConnection::handleRead(Timestamp receiveTime)
75 {
76!  int savedErrno = 0;
77!  ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);
78   if (n > 0) {
79!    messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);
80   } else if (n == 0) {
81     handleClose();
82   } else {
83+    errno = savedErrno;
84+    LOG_SYSERR << "TcpConnection::handleRead";
85     handleError();
86   }
87 }
88 
89 void TcpConnection::handleWrite()
90 {
91 }
92 
93 void TcpConnection::handleClose()
94 {
95   loop_->assertInLoopThread();
96   LOG_TRACE << "TcpConnection::handleClose state = " << state_;
97   assert(state_ == kConnected);
98   // we don't close fd, leave it to dtor, so we can find leaks easily.
99   channel_->disableAll();
100   // must be the last line
101   closeCallback_(shared_from_this());
102 }
103 
104 void TcpConnection::handleError()
105 {
106   int err = sockets::getSocketError(channel_->fd());
107   LOG_ERROR << "TcpConnection::handleError [" << name_
108             << "] - SO_ERROR = " << err << " " << strerror_tl(err);
109 }
110