tdaq-develop-2025-02-12
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 &&
39  (fSocketId = ::socket(AF_INET, SOCK_STREAM, 0)) == invalidSocketId)
40  throw std::runtime_error(std::string("Bad socket: ") + strerror(errno));
41 }
42 
43 //==============================================================================
44 void TCPSocket::close(void)
45 {
46  if(fSocketId == invalidSocketId)
47  {
48  throw std::logic_error("Bad socket object (this object was moved)");
49  }
50  int state = ::close(fSocketId);
51  std::cout << __PRETTY_FUNCTION__ << "Socket id: " << getSocketId()
52  << " close state: " << state << " errno: " << errno << std::endl;
53  if(state == 0) // 0 means socket closed correctly
54  fSocketId = invalidSocketId;
55  else
56  {
57  switch(errno)
58  {
59  case EBADF:
60  throw std::domain_error(std::string("Close: EBADF: ") +
61  std::to_string(fSocketId) + " " + strerror(errno));
62  case EIO:
63  throw std::runtime_error(std::string("Close: EIO: ") +
64  std::to_string(fSocketId) + " " + strerror(errno));
65  case EINTR: {
66  // TODO: Check for user interrupt flags.
67  // Beyond the scope of this project
68  // so continue normal operations.
69  return;
70  }
71  default:
72  throw std::runtime_error(std::string("Close: ???: ") +
73  std::to_string(fSocketId) + " " + strerror(errno));
74  }
75  }
76 }
77 
78 //==============================================================================
79 void TCPSocket::swap(TCPSocket& other)
80 {
81  using std::swap;
82  swap(fSocketId, other.fSocketId);
83 }
84 
85 //==============================================================================
86 TCPSocket::TCPSocket(TCPSocket&& move) : fSocketId(invalidSocketId) { move.swap(*this); }
87 
88 //==============================================================================
89 TCPSocket& TCPSocket::operator=(TCPSocket&& move)
90 {
91  move.swap(*this);
92  return *this;
93 }
94 
95 //==============================================================================
96 void TCPSocket::sendClose()
97 {
98  if(::shutdown(getSocketId(), SHUT_WR) != 0)
99  {
100  throw std::domain_error(std::string("Shutdown: critical error: ") +
101  strerror(errno));
102  }
103 }
TCPSocket(int socketId=invalidSocketId)
Designed to be a base class not used used directly.
Definition: TCPSocket.cc:12