4 #include "otsdaq/NetworkUtilities/TCPServerBase.h"
5 #include "otsdaq/Macros/CoutMacros.h"
6 #include "otsdaq/NetworkUtilities/TCPTransmitterSocket.h"
10 #include <arpa/inet.h>
13 #include <sys/socket.h>
25 : fMaxNumberOfClients(maxNumberOfClients), fServerPort(serverPort), fAccept(true)
28 if(fMaxNumberOfClients == 0)
29 fMaxNumberOfClients = (unsigned)-1;
36 TCPServerBase::~TCPServerBase(
void)
38 __COUT__ <<
"Shutting down accept for socket: " << getSocketId() << std::endl;
40 while(fAcceptFuture.valid() && fAcceptFuture.wait_for(std::chrono::milliseconds(
41 100)) != std::future_status::ready)
43 __COUT__ <<
"Server accept still running" << std::endl;
52 void TCPServerBase::startAccept(
void)
54 struct sockaddr_in checkAddr;
55 socklen_t addrLen =
sizeof(checkAddr);
56 if(::getsockname(getSocketId(), (
struct sockaddr*)&checkAddr, &addrLen) == 0 &&
57 checkAddr.sin_port != 0)
59 __COUT__ <<
"Socket " << getSocketId() <<
" is already bound to port "
60 << ntohs(checkAddr.sin_port) << std::endl;
66 if(::setsockopt(getSocketId(), SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof(
int)) == -1)
69 __SS__ <<
"Setsockopt: " << strerror(errno) << __E__;
73 struct sockaddr_in serverAddr;
74 bzero((
char*)&serverAddr,
sizeof(serverAddr));
75 serverAddr.sin_family = AF_INET;
76 serverAddr.sin_port = htons(fServerPort);
77 serverAddr.sin_addr.s_addr = INADDR_ANY;
79 if(::bind(getSocketId(), (
struct sockaddr*)&serverAddr,
sizeof(serverAddr)) != 0)
82 __SS__ <<
"Bind to port " << std::to_string(fServerPort) <<
": "
83 << strerror(errno) << __E__;
88 if(::listen(getSocketId(), fMaxConnectionBacklog) != 0)
91 __SS__ <<
"Listen on port " << std::to_string(fServerPort) <<
": "
92 << strerror(errno) << __E__;
98 std::async(std::launch::async, &TCPServerBase::acceptConnections,
this);
104 int TCPServerBase::accept(
bool blocking)
106 __COUT__ <<
"Now server accept connections on socket: " << getSocketId() << std::endl;
107 if(getSocketId() == invalidSocketId)
109 __SS__ <<
"Accept called on a bad socket object (this object was moved)" << __E__;
113 struct sockaddr_storage clientAddress;
114 socklen_t clientAddressSize =
sizeof(clientAddress);
115 int clientSocket = invalidSocketId;
122 std::lock_guard<std::mutex> lock(fClientsMutex);
123 __COUT__ <<
"Client list on input:\n";
124 for(
auto it = fConnectedClients.begin(); it != fConnectedClients.end(); it++)
126 __COUT__ <<
" --> Client: " << it->first <<
" : " << it->second
132 clientSocket = ::accept(
133 getSocketId(), (
struct sockaddr*)&clientAddress, &clientAddressSize);
134 __COUT__ <<
": clientSocket returned = " << clientSocket << std::endl;
136 bool tooMany =
false;
138 std::lock_guard<std::mutex> lock(fClientsMutex);
139 tooMany = fAccept && fMaxNumberOfClients > 0 &&
140 fConnectedClients.size() >= fMaxNumberOfClients;
144 send(clientSocket,
"Too many clients connected!", 27, 0);
145 ::shutdown(clientSocket, SHUT_WR);
150 __COUT__ <<
"fAccept? " << fAccept << std::endl;
155 else if(clientSocket == invalidSocketId)
157 __COUT__ <<
"New socket invalid?: " << clientSocket <<
" errno: " << errno
159 __SS__ <<
"Accept: " << strerror(errno) << __E__;
163 __COUT__ <<
"Server just accepted a connection on socket: " << getSocketId()
164 <<
" Client socket: " << clientSocket << std::endl;
169 constexpr
int sleepMSeconds = 5;
170 constexpr
int timeoutSeconds = 0;
171 constexpr
int timeoutUSeconds = 1000;
172 struct timeval timeout;
173 timeout.tv_sec = timeoutSeconds;
174 timeout.tv_usec = timeoutUSeconds;
181 FD_SET(getSocketId(), &fdSet);
182 select(getSocketId() + 1, &fdSet, 0, 0, &timeout);
184 if(FD_ISSET(getSocketId(), &fdSet))
186 struct sockaddr_in clientAddress;
187 socklen_t socketSize =
sizeof(clientAddress);
189 clientSocket = ::accept(
191 (
struct sockaddr*)&clientAddress,
193 if(clientSocket == invalidSocketId)
195 __COUT__ <<
"New socket invalid?: " << clientSocket
196 <<
" errno: " << errno << std::endl;
197 __SS__ <<
"Accept: " << strerror(errno) << __E__;
202 std::this_thread::sleep_for(std::chrono::milliseconds(sleepMSeconds));
210 void TCPServerBase::closeClientSockets(
void)
212 for(
auto& socket : fConnectedClients)
216 socket.second->sendClose();
218 catch(
const std::exception& e)
222 __COUT__ << e.what() <<
'\n';
225 auto clientThread = fConnectedClientsFuture.find(socket.first);
226 if(clientThread != fConnectedClientsFuture.end())
227 clientThread->second.wait();
228 delete socket.second;
230 fConnectedClients.clear();
231 fConnectedClientsFuture.clear();
237 std::lock_guard<std::mutex> lock(fClientsMutex);
238 auto it = fConnectedClients.find(socketId);
239 if(it == fConnectedClients.end())
241 auto clientThread = fConnectedClientsFuture.find(socketId);
242 if(clientThread != fConnectedClientsFuture.end())
243 fConnectedClientsFuture.erase(clientThread);
245 fConnectedClients.erase(it);
246 __COUT__ <<
"Removed disconnected client socket " << socketId <<
", "
247 << fConnectedClients.size() <<
" remaining." << std::endl;
253 std::lock_guard<std::mutex> lock(fClientsMutex);
254 std::vector<int> ids;
255 ids.reserve(fConnectedClients.size());
256 for(
auto const& client : fConnectedClients)
257 ids.push_back(client.first);
262 void TCPServerBase::closeClientSocket(
int socket)
265 std::lock_guard<std::mutex> lock(fClientsMutex);
266 auto it = fConnectedClients.find(socket);
267 if(it != fConnectedClients.end())
269 if(it->second->getSocketId() == socket)
273 if(it->second !=
nullptr)
274 it->second->sendClose();
276 catch(
const std::exception& e)
280 __COUT__ << e.what() <<
'\n';
283 fConnectedClients.erase(it);
288 <<
"SocketId in fConnectedClients != socketId in TCPSocket! Impossible!!!"
296 void TCPServerBase::broadcastPacket(
const char* message, std::size_t length)
298 broadcastPacket(std::string(message, length));
302 void TCPServerBase::broadcastPacket(
const std::string& message)
304 std::lock_guard<std::mutex> lock(fClientsMutex);
305 for(
auto it = fConnectedClients.begin(); it != fConnectedClients.end(); it++)
311 sock->sendPacket(message);
313 catch(
const std::exception& e)
319 if(fConnectedClientsFuture.find(it->first) != fConnectedClientsFuture.end())
320 fConnectedClientsFuture.erase(fConnectedClientsFuture.find(it->first));
322 fConnectedClients.erase(it--);
328 void TCPServerBase::broadcast(
const char* message, std::size_t length)
330 std::lock_guard<std::mutex> lock(fClientsMutex);
331 for(
auto it = fConnectedClients.begin(); it != fConnectedClients.end(); it++)
337 sock->send(message, length);
339 catch(
const std::exception& e)
345 if(fConnectedClientsFuture.find(it->first) != fConnectedClientsFuture.end())
346 fConnectedClientsFuture.erase(fConnectedClientsFuture.find(it->first));
348 fConnectedClients.erase(it--);
354 void TCPServerBase::broadcast(
const std::string& message)
356 std::lock_guard<std::mutex> lock(fClientsMutex);
357 for(
auto it = fConnectedClients.begin(); it != fConnectedClients.end(); it++)
365 catch(
const std::exception& e)
371 if(fConnectedClientsFuture.find(it->first) != fConnectedClientsFuture.end())
372 fConnectedClientsFuture.erase(fConnectedClientsFuture.find(it->first));
374 fConnectedClients.erase(it--);
380 void TCPServerBase::broadcast(
const std::vector<char>& message)
382 std::lock_guard<std::mutex> lock(fClientsMutex);
383 for(
auto it = fConnectedClients.begin(); it != fConnectedClients.end(); it++)
391 catch(
const std::exception& e)
397 if(fConnectedClientsFuture.find(it->first) != fConnectedClientsFuture.end())
398 fConnectedClientsFuture.erase(fConnectedClientsFuture.find(it->first));
400 fConnectedClients.erase(it--);
406 void TCPServerBase::broadcast(
const std::vector<uint16_t>& message)
408 std::lock_guard<std::mutex> lock(fClientsMutex);
409 for(
auto it = fConnectedClients.begin(); it != fConnectedClients.end(); it++)
417 catch(
const std::exception& e)
420 __COUT__ <<
"Error: " << e.what() << std::endl;
421 if(fConnectedClientsFuture.find(it->first) != fConnectedClientsFuture.end())
423 __COUT__ <<
"Removing client entry from future connected clients list\n";
424 fConnectedClientsFuture.erase(fConnectedClientsFuture.find(it->first));
426 __COUT__ <<
"Removing client entry from connected clients list\n";
428 fConnectedClients.erase(it--);
434 void TCPServerBase::pingActiveClients()
436 std::lock_guard<std::mutex> lock(fClientsMutex);
437 for(
auto it = fConnectedClients.begin(); it != fConnectedClients.end(); it++)
439 __COUT__ <<
"Pinging client " << it->first <<
" : " << it->second << std::endl;
444 sock->send(
"", 0,
true);
446 catch(
const std::exception& e)
451 __COUT__ <<
"Error: " << e.what() << std::endl;
452 if(fConnectedClientsFuture.find(it->first) != fConnectedClientsFuture.end())
454 __COUT__ <<
"Removing client entry from future connected clients list\n";
455 fConnectedClientsFuture.erase(fConnectedClientsFuture.find(it->first));
457 __COUT__ <<
"Removing client entry from connected clients list\n";
459 fConnectedClients.erase(it--);
465 void TCPServerBase::shutdownAccept()
468 shutdown(getSocketId(), SHUT_RD);
TCPServerBase(unsigned int serverPort, unsigned int maxNumberOfClients=0)
Means as many unsigned allows.
void removeClient(int socketId)
Drop a client whose peer has gone away (no shutdown handshake, just close).
std::vector< int > getClientSocketIds(void) const
Snapshot of connected client socket ids, safe to call from any thread.
A class that can write to a socket.
defines used also by OtsConfigurationWizardSupervisor