otsdaq  v2_04_02
TCPServerBase.cc
1 //#ifndef BEAGLEBONE
2 //#include "otsdaq_cmsburninbox/BeagleBone/BeagleBoneUtils/TCPServerBase.h"
3 //#else
4 #include "otsdaq/NetworkUtilities/TCPServerBase.h"
5 #include "otsdaq/NetworkUtilities/TCPTransmitterSocket.h"
6 //#endif
7 
8 #include <arpa/inet.h>
9 #include <errno.h> // errno
10 #include <string.h> // errno
11 #include <iostream>
12 
13 using namespace ots;
14 
15 //========================================================================================================================
16 TCPServerBase::TCPServerBase(int serverPort, unsigned int maxNumberOfClients)
17  : fMaxNumberOfClients(maxNumberOfClients)
18  , fAccept(true)
19  , fAcceptFuture(fAcceptPromise.get_future())
20 {
21  int opt = 1; // SO_REUSEADDR - man socket(7)
22  if(::setsockopt(getSocketId(), SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) != 0)
23  {
24  close();
25  throw std::runtime_error(std::string("Setsockopt: ") + strerror(errno));
26  }
27 
28  struct sockaddr_in serverAddr;
29  bzero((char*)&serverAddr, sizeof(serverAddr));
30  serverAddr.sin_family = AF_INET;
31  serverAddr.sin_port = htons(serverPort);
32  serverAddr.sin_addr.s_addr = INADDR_ANY;
33 
34  if(::bind(getSocketId(), (struct sockaddr*)&serverAddr, sizeof(serverAddr)) != 0)
35  {
36  close();
37  throw std::runtime_error(std::string("Bind: ") + strerror(errno));
38  }
39 
40  if(::listen(getSocketId(), fMaxConnectionBacklog) != 0)
41  {
42  close();
43  throw std::runtime_error(std::string("Listen: ") + strerror(errno));
44  }
45  startAccept();
46 }
47 
48 //========================================================================================================================
49 TCPServerBase::~TCPServerBase(void)
50 {
51  std::cout << __PRETTY_FUNCTION__
52  << "Closing the network server socket: " << getSocketId() << std::endl;
53  std::cout << __PRETTY_FUNCTION__
54  << "SHUTDOWN Closing the network server socket: " << getSocketId()
55  << std::endl;
56  shutdownAccept();
57  std::cout << __PRETTY_FUNCTION__
58  << "Closing the network server socket: " << getSocketId() << std::endl;
59  while(fAcceptFuture.wait_for(std::chrono::milliseconds(100)) !=
60  std::future_status::ready)
61  std::cout << __PRETTY_FUNCTION__ << "Still running" << std::endl;
62  closeClientSockets();
63  std::cout << __PRETTY_FUNCTION__
64  << "Closed all sockets connected to server: " << getSocketId() << std::endl;
65 }
66 
67 //========================================================================================================================
68 void TCPServerBase::startAccept(void)
69 {
70  std::thread thread(&TCPServerBase::acceptConnections, this);
71  thread.detach();
72 }
73 
74 // An accepts waits for a connection and returns the opened socket number
75 //========================================================================================================================
76 int TCPServerBase::accept(bool blocking)
77 {
78  std::cout << __PRETTY_FUNCTION__
79  << "Now server accept connections on socket: " << getSocketId()
80  << std::endl;
81  if(getSocketId() == invalidSocketId)
82  {
83  throw std::logic_error(
84  "Accept called on a bad socket object (this object was moved)");
85  }
86 
87  struct sockaddr_storage serverStorage;
88  socklen_t addr_size = sizeof serverStorage;
89  int clientSocket = invalidSocketId;
90  if(blocking)
91  {
92  clientSocket =
93  ::accept(getSocketId(), (struct sockaddr*)&serverStorage, &addr_size);
94  if(!fAccept)
95  {
96  fAccept = true;
97  throw E_SHUTDOWN;
98  }
99  if(clientSocket == invalidSocketId)
100  {
101  std::cout << __PRETTY_FUNCTION__ << "New socket invalid?: " << clientSocket
102  << " errno: " << errno << std::endl;
103  throw std::runtime_error(std::string("Accept: ") + strerror(errno));
104  }
105  std::cout << __PRETTY_FUNCTION__
106  << "Server just accepted a connection on socket: " << getSocketId()
107  << " Client socket: " << clientSocket << std::endl;
108  return clientSocket;
109  }
110  else
111  {
112  constexpr int sleepMSeconds = 5;
113  constexpr int timeoutSeconds = 0;
114  constexpr int timeoutUSeconds = 1000;
115  struct timeval timeout;
116  timeout.tv_sec = timeoutSeconds;
117  timeout.tv_usec = timeoutUSeconds;
118 
119  fd_set fdSet;
120 
121  while(fAccept)
122  {
123  FD_ZERO(&fdSet);
124  FD_SET(getSocketId(), &fdSet);
125  select(getSocketId() + 1, &fdSet, 0, 0, &timeout);
126 
127  if(FD_ISSET(getSocketId(), &fdSet))
128  {
129  struct sockaddr_in clientAddress;
130  socklen_t socketSize = sizeof(clientAddress);
131  // int newSocketFD = ::accept4(fdServerSocket_,(struct
132  // sockaddr*)&clientAddress,&socketSize, (pushOnly_ ? SOCK_NONBLOCK : 0));
133  clientSocket = ::accept(getSocketId(),
134  (struct sockaddr*)&clientAddress,
135  &socketSize); // Blocking since select goes in
136  // timeout if there is nothing
137  if(clientSocket == invalidSocketId)
138  {
139  std::cout << __PRETTY_FUNCTION__
140  << "New socket invalid?: " << clientSocket
141  << " errno: " << errno << std::endl;
142  throw std::runtime_error(std::string("Accept: ") + strerror(errno));
143  }
144  return clientSocket;
145  }
146  std::this_thread::sleep_for(std::chrono::milliseconds(sleepMSeconds));
147  }
148  fAccept = true;
149  throw E_SHUTDOWN;
150  }
151 }
152 
153 //========================================================================================================================
154 void TCPServerBase::closeClientSockets(void)
155 {
156  for(auto& socket : fConnectedClients)
157  {
158  socket.second->sendClose();
159  delete socket.second;
160  }
161  fConnectedClients.clear();
162 }
163 
164 //========================================================================================================================
165 void TCPServerBase::closeClientSocket(int socket)
166 {
167  for(auto it = fConnectedClients.begin(); it != fConnectedClients.end(); it++)
168  if(it->second->getSocketId() == socket)
169  {
170  it->second->sendClose();
171  delete it->second;
172  fConnectedClients.erase(it);
173  }
174 }
175 
176 //========================================================================================================================
177 void TCPServerBase::broadcastPacket(const std::string& message)
178 {
179  for(auto& socket : fConnectedClients)
180  dynamic_cast<TCPTransmitterSocket*>(socket.second)->sendPacket(message);
181 }
182 
183 //========================================================================================================================
184 void TCPServerBase::broadcast(const std::string& message)
185 {
186  for(auto& socket : fConnectedClients)
187  dynamic_cast<TCPTransmitterSocket*>(socket.second)->send(message);
188 }
189 
190 //========================================================================================================================
191 void TCPServerBase::broadcast(const std::vector<char>& message)
192 {
193  for(auto& socket : fConnectedClients)
194  dynamic_cast<TCPTransmitterSocket*>(socket.second)->send(message);
195 }
196 
197 //========================================================================================================================
198 void TCPServerBase::shutdownAccept()
199 {
200  fAccept = false;
201  shutdown(getSocketId(), SHUT_RD);
202 }