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