1#include "TcpStream.h"
2#include "InetAddress.h"
3
4#include <errno.h>
5#include <signal.h>
6#include <unistd.h>
7#include <sys/socket.h>
8
9namespace
10{
11
12class IgnoreSigPipe
13{
14 public:
15  IgnoreSigPipe()
16  {
17    ::signal(SIGPIPE, SIG_IGN);
18  }
19} initObj;
20
21bool isSelfConnection(const Socket& sock)
22{
23  return sock.getLocalAddr() == sock.getPeerAddr();
24}
25
26}
27
28TcpStream::TcpStream(Socket&& sock)
29  : sock_(std::move(sock))
30{
31}
32
33int TcpStream::receiveAll(void* buf, int len)
34{
35#ifdef TEMP_FAILURE_RETRY
36  return TEMP_FAILURE_RETRY(::recv(sock_.fd(), buf, len, MSG_WAITALL));
37#else
38  return ::recv(sock_.fd(), buf, len, MSG_WAITALL);
39#endif
40}
41
42int TcpStream::receiveSome(void* buf, int len)
43{
44  return sock_.recv(buf, len);
45}
46
47int TcpStream::sendAll(const void* buf, int len)
48{
49  int written = 0;
50  while (written < len)
51  {
52    int nw = sock_.send(static_cast<const char*>(buf) + written, len - written);
53    if (nw > 0)
54    {
55      written += nw;
56    }
57    else
58    {
59      break;
60    }
61  }
62  return written;
63}
64
65int TcpStream::sendSome(const void* buf, int len)
66{
67  return sock_.send(buf, len);
68}
69
70void TcpStream::setTcpNoDelay(bool on)
71{
72  sock_.setTcpNoDelay(on);
73}
74
75void TcpStream::shutdownWrite()
76{
77  sock_.shutdownWrite();
78}
79
80TcpStreamPtr TcpStream::connect(const InetAddress& serverAddr)
81{
82  return connectInternal(serverAddr, nullptr);
83}
84
85TcpStreamPtr TcpStream::connect(const InetAddress& serverAddr, const InetAddress& localAddr)
86{
87  return connectInternal(serverAddr, &localAddr);
88}
89
90TcpStreamPtr TcpStream::connectInternal(const InetAddress& serverAddr, const InetAddress* localAddr)
91{
92  TcpStreamPtr stream;
93  Socket sock(Socket::createTCP(serverAddr.family()));
94  if (localAddr)
95  {
96    sock.bindOrDie(*localAddr);
97  }
98  if (sock.connect(serverAddr) == 0 && !isSelfConnection(sock))
99  {
100    // FIXME: do poll(POLLOUT) to check errors
101    stream.reset(new TcpStream(std::move(sock)));
102  }
103  return stream;
104}
105