otsdaq  v2_05_02_indev
TCPSocket.cc
1 #include "otsdaq/NetworkUtilities/TCPSocket.h"
2 #include <string.h>
3 #include <sys/socket.h>
4 #include <sys/time.h>
5 #include <unistd.h>
6 #include <iostream>
7 #include <stdexcept>
8 
9 using namespace ots;
10 
11 //==============================================================================
12 TCPSocket::TCPSocket(int socketId) : fSocketId(socketId) { open(); }
13 
14 //==============================================================================
15 TCPSocket::~TCPSocket()
16 {
17  try
18  {
19  close();
20  std::cout << __PRETTY_FUNCTION__ << "Clean close!" << std::endl;
21  }
22  catch(...)
23  {
24  // We should log this
25  // TODO: LOGGING CODE HERE
26 
27  // If the user really want to catch close errors
28  // they should call close() manually and handle
29  // any generated exceptions. By using the
30  // destructor they are indicating that failures is
31  // an OK condition.
32  }
33 }
34 
35 //==============================================================================
36 void TCPSocket::open(void)
37 {
38  if(fSocketId == invalidSocketId && (fSocketId = ::socket(PF_INET, SOCK_STREAM, 0)) == invalidSocketId)
39  throw std::runtime_error(std::string("Bad socket: ") + strerror(errno));
40 }
41 
42 //==============================================================================
43 void TCPSocket::close(void)
44 {
45  if(fSocketId == invalidSocketId)
46  {
47  throw std::logic_error("Bad socket object (this object was moved)");
48  }
49  int state = ::close(fSocketId);
50  std::cout << __PRETTY_FUNCTION__ << "Socket id: " << getSocketId() << " close state: " << state << " errno: " << errno << std::endl;
51  if(state == 0) // 0 means socket closed correctly
52  fSocketId = invalidSocketId;
53  else
54  {
55  switch(errno)
56  {
57  case EBADF:
58  throw std::domain_error(std::string("Close: EBADF: ") + std::to_string(fSocketId) + " " + strerror(errno));
59  case EIO:
60  throw std::runtime_error(std::string("Close: EIO: ") + std::to_string(fSocketId) + " " + strerror(errno));
61  case EINTR:
62  {
63  // TODO: Check for user interrupt flags.
64  // Beyond the scope of this project
65  // so continue normal operations.
66  return;
67  }
68  default:
69  throw std::runtime_error(std::string("Close: ???: ") + std::to_string(fSocketId) + " " + strerror(errno));
70  }
71  }
72 }
73 
74 //==============================================================================
75 void TCPSocket::swap(TCPSocket& other)
76 {
77  using std::swap;
78  swap(fSocketId, other.fSocketId);
79 }
80 
81 //==============================================================================
82 TCPSocket::TCPSocket(TCPSocket&& move) : fSocketId(invalidSocketId) { move.swap(*this); }
83 
84 //==============================================================================
85 TCPSocket& TCPSocket::operator=(TCPSocket&& move)
86 {
87  move.swap(*this);
88  return *this;
89 }
90 
91 //==============================================================================
92 void TCPSocket::sendClose()
93 {
94  if(::shutdown(getSocketId(), SHUT_WR) != 0)
95  {
96  throw std::domain_error(std::string("Shutdown: critical error: ") + strerror(errno));
97  }
98 }