UDP socket problem - c++

I'm writing a multiplayer game (obviously using UDP sockets. note: using winsock 2.2). The server code reads something like this:
while(run)
{
select(0, &readSockets, NULL, NULL, &t)
if(FD_ISSET(serverSocket, &readSockets))
{
printf("%s\n","Data receieved");
//recvfrom over here
}
FD_SET(serverSocket, &readSockets);
}
While this is not receiving data from my client, this is:
recvfrom(serverSocket, buffer, sizeof(buffer), 0, &client, &client_size);

One possible issue here is possibly the select() call. I believe the first parameter needs to be the highest socket number +1.

The FD_SET is at the end of the loop so it looks like your first call to select() may have an empty or uninitialized fd_set. Make sure you use FD_ZERO(&readSockets) and FD_SET(serverSocket, &readSockets) before your loop. Also it would be good to check for errors on the select() call.

Hmmm... after fiddling with the code a bit, I found these lines:
console->clear();
console->resetCursorPosition();
So, it was receiving data, but the message on the console was getting erased instantly. [sigh]

You are supposed to check for errors returned by select(). On Windows this would be something like:
if (( nret = select( nfds, &rset, &wset, &eset, &to )) == SOCKET_ERROR )
{
// error handling, probably with WSAGetLastError()
// ...
}
Since it looks like you are using a timeout, select() can also return zero, i.e. no socket descriptors are ready, but timeout expired.

Related

C++ + linux handle SIGPIPE signal

Yes, I understand this issue has been discussed many times.
And yes, I've seen and read these and other discussions:
1
2
3
and I still can't fix my code myself.
I am writing my own web server. In the next cycle, it listens on a socket, connects each new client and writes it to a vector.
Into my class i have this struct:
struct Connection
{
int socket;
std::chrono::system_clock::time_point tp;
std::string request;
};
with next data structures:
std::mutex connected_clients_mux_;
std::vector<HttpServer::Connection> connected_clients_;
and the cycle itself:
//...
bind (listen_socket_, (struct sockaddr *)&addr_, sizeof(addr_));
listen(listen_socket_, 4 );
while(1){
connection_socket_ = accept(listen_socket_, NULL, NULL);
//...
Connection connection_;
//...
connected_clients_mux_.lock();
this->connected_clients_.push_back(connection_);
connected_clients_mux_.unlock();
}
it works, clients connect, send and receive requests.
But the problem is that if the connection is broken ("^C" for client), then my program will not know about it even at the moment:
void SendRespons(HttpServer::Connection socket_){
write(socket_.socket,( socket_.request + std::to_string(socket_.socket)).c_str(), 1024);
}
as the title of this question suggests, my app receives a SIGPIPE signal.
Again, I have seen "solutions".
signal(SIGPIPE, &SigPipeHandler);
void SigPipeHandler(int s) {
//printf("Caught SIGPIPE\n%d",s);
}
but it does not help. At this moment, we have the "№" of the socket to which the write was made, is it possible to "remember" it and close this particular connection in the handler method?
my system:
Operating System: Ubuntu 20.04.2 LTS
Kernel: Linux 5.8.0-43-generic
g++ --version
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
As stated in the links you give, the solution is to ignore SIGPIPE, and CHECK THE RETURN VALUE of the write calls. This latter is needed for correct operation (short writes) in all but the most trivial, unloaded cases anyways. Also the fixed write size of 1024 that you are using is probably not what you want -- if your response string is shorter, you'll send a bunch of random garbage along with it. You probably really want something like:
void SendRespons(HttpServer::Connection socket_){
auto data = socket_.request + std::to_string(socket_.socket);
int sent = 0;
while (sent < data.size()) {
int len = write(socket_.socket, &data[sent], data.size() - sent);
if (len < 0) {
// there was an error -- might be EPIPE or EAGAIN or EINTR or ever a few other
// obscure corner cases. For EAGAIN or EINTR (which can only happen if your
// program is set up to allow them), you probably want to try again.
// Anything else, probably just close the socket and clean up.
if (errno == EINTR)
continue;
close(socket_.socket);
// should tell someone about it?
break; }
sent += len; }
}

How to stop a C++ blocking read call

I'm reading CAN-BUS traffic under SocketCAN and C++ in GNU/Linux. I've found that the read call is blocking, and I'm struggling to figure out how to stop my program properly when I don't want to keep reading.
Of course, I could hit Ctrl+C if I've invoked the program from the terminal, but the point is to find a way to do it programmatically when some condition is met (e.g., record for 5 seconds, or when some event happens, like a flag is raised). A timeout could work, or something like a signal, but I don't know how to do it properly.
// Read (blocking)
nbytes = read(s, &frame, sizeof(struct can_frame));
You don't.
Use a method like select or epoll to determine whether the socket has activity before beginning the read. Then it will not actually block.
The select/epoll call is itself blocking, but can be given a timeout so that you always have an escape route (or, in the case of epoll, the lovely epollfd for immediate triggering of a breakout).
Read is always blocking... you want to only read if data is waiting... so consider doing a poll on the socket first to see if data is available and if so THEN read it. You can loop over doing the poll until you no longer want to read anymore...
bool pollIn(int fd)
{
bool returnValue{false};
struct pollfd *pfd;
pfd = calloc(1, sizeof(struct pollfd));
pfd.fd = fd;
pfd.events = POLLIN;
int pollReturn{-1};
pollReturn = poll(pfd, 1, 0);
if (pollReturn > 0)
{
if (pfd.revents & POLLIN)
{
returnValue = true;
}
}
free(pfd);
return(returnValue);
}
The above should return if there is data waiting at the socket file descriptor.
while(!exitCondition)
{
if(pollIn(fd))
{
nbytes = read(fd, &frame, sizeof(struct can_frame));
// other stuff you need to do with your read
}
}

udp select timeout issues. Either timing out or reading from all clients

I am using select to handle connections on a udp server. If I do not get a packet for some period, I would like to time out. The probelm is, it seems I can either timeout correctly and only read from one client, or read from all clients and not time out.
The difference in this functionality has to do with the first argument to select, the int nfds
Here is my code:
int TIMEOUT = 5;
for (;;) {
FD_ZERO(&read_handles);
FD_SET(udpFD, &read_handles);
timeout.tv_sec = TIMEOUT;
timeout.tv_usec = 0;
if (select(udpFD+1, &read_handles, NULL, NULL, &timeout) == 0) {
printf("Select has timed out...\n");
return 1;
} else {
int length = 1;
if (FD_ISSET(udpFD, &read_handles)) {
//process read.
}
}
}
This version does not time out. If I change the select line to:
if(select(udpFD, &read_handles, NULL, NULL, &timeout) == 0)
It does timeout, but it only receives data from one of my clients.
udpFD is the only handle I am looking at, but it has a value of 4 because it is not the first descriptor I have made. I do not know if that makes a difference because it is the max value.
How can I both timeout and get data from both of my clients?
Using if(select(udpFD+1, &read_handles, NULL, NULL, &timeout) == 0) is the correct way to go.
This will work.
My error was later in the code I was not resetting a length field I read, and was getting stuck in the recvfrom loop, and only calling select once.

How can I clean up properly when recv is blocking?

Consider the example code below (I typed it up quickly as an example, if there are errors it doesn't matter - I'm interested in the theory).
bool shutDown = false; //global
int main()
{
CreateThread(NULL, 0, &MessengerLoop, NULL, 0, NULL);
//do other programmy stuff...
}
DWORD WINAPI MessengerLoop( LPVOID lpParam )
{
zmq::context_t context(1);
zmq::socket_t socket (context, ZMQ_SUB);
socket.connect("tcp://localhost:5556");
socket.setsockopt(ZMQ_SUBSCRIBE, "10001 ", 6);
while(!shutDown)
{
zmq_msg_t getMessage;
zmq_msg_init(&getMessage);
zmq_msg_recv (&getMessage, socket, 0); //This line will wait forever for a message
processMessage(getMessage);
}
}
A thread is created to wait for incoming messages and to handle them appropriately. The thread is looping until shutDown is set to true.
In ZeroMQ the Guide specifically states what must be cleaned up, namely the messages, socket and context.
My issue is: Since recv will wait forever for a message, blocking the thread, how can I shut down this thread safely if a message is never received?
The blocking call will exit in a few ways. First, and this depends on your language and binding, an interrupt (Ctrl-C, SIGINT, SIGTERM) will exit the call. You'll get back (again, depending on your binding) an error or a null message (libzmq returns an EINTR error).
Second, if you terminate the context in another thread, the blocking call will also exit (libzmq returns an ETERM error).
Thirdly, you can set timeouts on the socket so it will return in any case after some timeout, if there's no data. We don't often do this but it can be useful in some cases.
Finally, what we do in practice is never do blocking receives but use zmq_poll to find out when sockets have messages waiting, then receive from those sockets. This is how you scale out to handling more sockets.
You can use non-blocking call flag ZMQ_DONTWAIT
while(!shutDown)
{
zmq_msg_t getMessage;
zmq_msg_init(&getMessage);
while(-1 == zmq_msg_recv(&getMessage, socket, ZMQ_DONTWAIT))
{
if (EAGAIN != errno || shutDown)
{
break;
}
Sleep(100);
}
processMessage(getMessage);
}
Whenever zmq context is destroyed, zmq_msg_recv will receive a -1. I use this as the terminating condition in all of my code.
while (!shutdown)
{
..
..
int rc = zmq_msg_recv (&getMessage, socket, 0);
if (rc != -1)
{
processMessage;
}
else
break;
}
Remember to destroy the zmq context at the end of your main() for a proper clean-up.
zmq_ctx_destroy(zctx);
Lets say you have a class say SUB (subscriber) that manages the receive of your ZMQ messages. In the destructor or exit function of your main function/class, call the following:
pub->close();
///
/// Close the publish context
///
void PUB::close()
{
zmq_close (socket);
zmq_ctx_destroy (context);
}
This will enable that 'recv' blocking terminates with error message that you can ignore. The application will exit comfortably in the right way. This is the right method. Good luck!

C++ / Gloox: how to check when connection is down?

I'm trying to write own jabber bot on c++/gloox. Everything goes fine, but when internet connection is down - bot thinks that it's still connected, and when connection is up again - of course bot doesn't respond to any message.
Each time since bot is successfully connected gloox' recv() returns ConnNoError, even if interface is down and cable unplugged.
Tried use blocking and non-blocking gloox' connection and recv() and all was without any result. Periodic checks of availability of xmpp server in different thread is not seems like a good idea, so how to properly check is bot connected right now or no?
If it's not possible to do with gloox only - please point me on some good method, but let it be availible in unix.
I have the same question, and found the reason why recv always retrun ConnNoError. Here is what I found. When the connection is established, the recv calls a funciton named dataAvailable In ConnectionTCPBase.cpp which return
( ( select( m_socket + 1, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 ) && FD_ISSET( m_socket, &fds ) != 0 )
searching google, I found this thread, it said FD_ISSET( m_socket, &fds ) would detect the socket is readble but not is closed ... Return value of FD_ISSET( m_socket, &fds ) is always 0, even the network is down. In such case, the return value of dataAvailable is false, so the code below finally returns ConnNoError in recv.
if( !dataAvailable( timeout ) )
{
m_recvMutex.unlock();
return ConnNoError;
}
I don't know whether it is a bug or what, seems not.
Later I tried another way, write to the socket directly, and this will cause a SIGPIPE if the socket is closed, catch that signal, then use cleanup to disconnect.
I finally figure out a graceful solution to this problem, using heartbeat.
in the gloox thread, call heartBeat(), where m_pClient is an pointer to a instance of gloox::Client
void CXmpp::heartBeat()
{
m_pClient->xmppPing(m_pClient->jid(), this);
if (++heart) > 3) {
m_pClient->disconnect();
}
}
xmppPing will register itself to eventhandler, when ping comes back, it will call handleEvent, and in handleEvent
void CEventHandler::handleEvent(const Event& event)
{
std::string sEvent;
switch (event.eventType())
{
case Event::PingPing:
sEvent = "PingPing";
break;
case Event::PingPong:
sEvent = "PingPong";
//recieve from server, decrease the count of heart
--heart;
break;
case Event::PingError:
sEvent = "PingError";
break;
default:
break;
}
return;
}
connect to the server, turn off the network, 3 seconds later, I got a disconnect!
You have to define the onDisconnect(ConnectionError e) to be able to handle the disconnect event. The address to documentation is http://camaya.net/api/gloox-0.9.9.12/classgloox_1_1ConnectionListener.html#a2