Why is select() ignoring the timeout value? - c++

I'm new to networking and I want to write a simple, Client-side TCP/IP script; however, I encounter an issue when using select() to receive the server's answer.
I want to use select because I need the timeout functionality. I am using select() in a custom function with a non-zero timeout value, generating a DLL out of it, then calling the function in a client main().
Everything works as intended, except the timeout. Either I receive the message instantly (which is good), or the select() function times out instantly (which is not). It seems to me like the timeout value is not taken into account at all.
Here is the code I am using. I included the function in which select() is placed, as well as the client-side implementation.
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <time.h>
#pragma comment(lib, "Ws2_32.lib")
int ReceiveClientMessage()
{
int iResult = -1;
FD_SET ReadSet;
int Socket_notifs = 0;
struct timeval timeout;
timeout.tv_sec = 20000000;
timeout.tv_usec = 0;
FD_ZERO(&ReadSet);
FD_SET(socket_Client, &ReadSet);
Socket_notifs = select(0, &ReadSet, NULL, NULL, &timeout);
if (Socket_notifs == SOCKET_ERROR)
{
printf("Select returned with error %d\n", WSAGetLastError());
return 1;
}
printf("Select successful\n");
if (Socket_notifs > 0)
{
int receiving_buffer_length = DEFAULT_BUFLEN;
char receiving_buffer[DEFAULT_BUFLEN] = "";
// Start receiving
iResult = recv(socket_Client, receiving_buffer, receiving_buffer_length, 0);
if (iResult > 0)
// Message received, display save yada yada
else
// Error receiving
}
else if (Socket_notifs == 0)
{
// Timeout
printf("Select timed out\n\n");
return 2;
}
else
{
// Other issue with select
printf("Unknown error with Select\n\n");
return 3;
}
return 0;
}
//----------------------------------------------------------------
// Client main()
string message, response;
while (true)
{
/* Part where we send a message, irrelevant here */
// Receive a message on client side
iResult = -1;
iResult = ReceiveClientMessage();
cout << iResult << endl;
if (iResult != 0)
// Error, clean up and break
else
// Display message
}
I tried to remove most irrelevant parts of my code, and only left the parts relevant to the select, timeout and receive implementation.
I have already tried setting various values for timeout.tv_sec and timeout.tv_usec (from 20 to 20000000), in case it wasn't a value in seconds or something, without results. Sometimes I send a message, and instantly see the "Select timed out" prompt (which, from my understanding, should not happen). Any idea on how to solve this (either by finding out why the timeout values are not taken into account, or by using another method that has a timeout functionality)?

Related

timeout and select() not working as expected

I'm trying to communicate with a server using an rcon protocol to take control over a gamesever. So far I was using an exisiting C# library for this but this library is sometimes quite buggy and therefore I'm was writing my own application in C++ so that I'm able to use it both on windows and on my linux server.
So far this worked out pretty well but now I'm running into problems when I try to set a timeout using select() to find out if the server still started and responding to my commands. During the first run of the application select() always returns the right value, but after closing and running it again, results get weird.
My code pretty much looks like this:
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string.h>
#include <unistd.h>
// Socket Includes
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// Other Includes
#include "main.h"
#include "crc32.h"
int main() {
struct sockaddr_in server;
int mysocket, slen = sizeof(server);
char buffer[2048];
if ((mysocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
printf("error creating socket");
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");
server.sin_port = htons(1234);
if(connect(mysocket, (sockaddr*) &server, sizeof(server)) < 0)
printf("error connecting the socket");
bool isConnected = false;
/*
Creating the Packet to send, cut to save some space
*/
sendto(mysocket, loginPacket.c_str(), loginPacket.length(), 0, (sockaddr *) &server, slen);
while(1) {
// clearing the buffer
bzero(buffer, 2048);
// Timeout Settings
int selectSize = 0;
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
fd_set fds;
FD_ZERO(&fds);
FD_SET(mysocket, &fds);
selectSize = select(mysocket + 1, &fds, 0, 0, &timeout);
std::cout << "Size is: " selectSize << std::endl; // just for testing :)
if (selectSize == 1) {
int recvLength = recvfrom(mysocket, buffer, sizeof(buffer), 0, (sockaddr *) &server, (socklen_t*) &slen);
if (buffer[7] == 0x00) {
if (buffer[8] == 0x01) {
//password correct
isConnected = true;
break;
}
if (buffer[8] == 0x00) {
//password wrong, do sth.
}
}
}
}
// tests
sayHello();
close(mysocket);
return 0;
}
When I start the script for the first time and the server is not started, everything works as expected, after 5 seconds selectSize returns the value 0. It loops further on until I start the the server, then it will return value 1 and break the while loop. Afterwards I quit the application, turn off the server and start the script again. Instead of return value 0 after 5 seconds, it immediately returns value 1 (even though the server is offline and there's not packet to receive) and then after 5 seconds it will return value 0. Running the same script (with some adjustments) on windows gave me pretty much the same result, but selectSize pretty much always returned 1, even though the server was offline and the value should have been 0. I read tons of sites about using select() the right way but none of them helped me so far as select() is not returning reliable results after quitting and restarting the application.
P.S.: There was some confusing information about how to use select() the right way, I used pretty much every solution provided on the internet like:
selectSize = select(mysocket + 1, &fds, 0, 0, &timeout);
selectSize = select(0, &fds, 0, 0, &timeout);
selectSize = select(1, &fds, 0, 0, &timeout);
But none of them gave me a reliable result.

Windows UDP sockets: recvfrom() fails with error 10054

Hello everyone.
I'm trying to use Windows sockets to send and receive UDP packets (in C++).
It worked well until three days ago, when the program stopped behaving properly.
To summarize the situation:
When calling WSAPoll() on my socket, it always returns my socket updated with EVERY revents possible (corresponding to every events I gave the pollfd), even if there is no server launched.
When calling recvfrom() and no server is launched, it returns SOCKET_ERROR with error code 10054(*).
When calling recvfrom() and a server is launched, it works properly - blocks until it receives something.
The behavior is the same whether I try to connect to localhost or to a distant host.
(*) I investigated this error. In UDP, it means that there is an ICMP problem. ("On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.").
I indeed call sendto() before recvfrom(), so the problem's not here.
I tried to put down my firewall to see if it changed anything, but it didn't. I also tried to put down every network flowing through my PC. In this state I managed to get the program to work for a few minutes, but when I enabled the networks it stopped working again. I tried to repeat the process but it would not work anymore.
I tried compiling with both visual studio (2015) and MinGW.
I tried on another computer too (under Windows 7, mine has Windows 8.1), to no avail.
Here is a simple test file which does not work on my computer.
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x501
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <vector>
#include <iostream>
int main() {
int clientSock;
char buf[100];
int serverPort;
/* Initializing WSA */
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
/* I create my socket */
struct addrinfo specs;
struct addrinfo *addr = new addrinfo;
ZeroMemory(&specs, sizeof(specs));
specs.ai_family = AF_INET;
specs.ai_socktype = SOCK_DGRAM;
specs.ai_flags = 0;
getaddrinfo("127.0.0.1", "2324", &specs, &addr);
clientSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
/* I get the server's address */
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
serverAddr.sin_port = htons(2324);
int len = sizeof(struct sockaddr);
/* I'll poll & recvfrom on my socket */
std::vector<pollfd> fds;
pollfd fd;
fd.fd = clientSock;
fd.events = POLLRDNORM;
fd.revents = -1;
fds.push_back(fd);
while(1) {
memset(buf,0,sizeof(buf));
printf("\nClient--->: ");
gets(buf);
/* It's UDP, so it doesn't matter if there is someone to receive the packet */
sendto(clientSock, buf, strlen(buf), 0, (sockaddr*)&serverAddr ,len);
memset(buf,0,sizeof(buf));
int ret;
/* Always returns "1" */
if ((ret = WSAPoll(fds.data(), 1, 0)) > 0) {
std::cout << ret;
/* Always returns "-1" */
std::cout << recvfrom(clientSock,buf,sizeof(buf),0, (sockaddr*)&serverAddr,&len) << std::endl;
printf("\n--->From the server: ");
printf("%s",buf);
}
}
closesocket(clientSock);
WSACleanup();
return 0;
}
Two questions:
Why does WSAPoll() always returns an updated socket, even if there wasn't any interaction with it ?
Why does recvfrom() return this error and how can I fix it ? I suppose it comes from my computer. I tried allowing ICMP through my firewall but it didn't change anything, maybe I did something wrong ?
Edit: I fixed my main program (not shown here because it is way too large) by just ignoring any "error 10054" I received. Now it works the same way it does on Unix.
Still, it is not really a solution (ignoring an error code... meh) and if anyone knows why I get the "ICMP Port Unreachable" error when calling sendto(), I'd be glad to hear about it.
In Windows, if host A use UDP socket and call sendto() to send something to host B, but B doesn't bind any port so that B doesn't receive the message, and then host A call recvfrom() to receive some message, recvfrom() will failed, and WSAGetLastError() will return 10054.
It's a bug of Windows. If UDP socket recv a ICMP(port unreachable) message after send a message, this error will be stored, and next time call recvfrom() will return this error.
There are 2 ways to solve this problem:
Make sure host B has already bound the port you want to send to.
Disable this error by using following code:
#include <Winsock2.h>
#include <Mstcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
BOOL bNewBehavior = FALSE;
DWORD dwBytesReturned = 0;
WSAIoctl(iSock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL);
Reference:
http://www.cnblogs.com/cnpirate/p/4059137.html
I have stripped down the Authors code and included the fix of simmerlee. This provides an simpler way to reproduce the error:
#include "stdafx.h"
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
void testCase(bool fixed)
{
int clientSock;
char rcvBuf[100];
// create socket
clientSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(fixed)
{
BOOL bNewBehavior = FALSE;
DWORD dwBytesReturned = 0;
WSAIoctl(clientSock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL);
}
// bind socket
struct sockaddr_in clientAddr;
clientAddr.sin_family = AF_INET;
clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
clientAddr.sin_port = htons(61234);
int sizeClientAddr = sizeof(clientAddr);
bind(clientSock, (sockaddr*) &clientAddr, sizeClientAddr);
struct sockaddr_in serverAddr = clientAddr;
serverAddr.sin_port = htons(2324); // change port where nobody listens
int sizeServerAddr = sizeof(struct sockaddr);
int lasterror = 0;
int status = 0;
// send where nobody is listening
printf("Send to nowhere--->:\n");
/* It's UDP, so it doesn't matter if there is someone to receive the packet */
status =sendto(clientSock, "Message", 7, 0, (sockaddr*)&serverAddr, sizeServerAddr);
lasterror = WSAGetLastError();
printf("sendto return %d (lasterror %d)\n", status, lasterror);
// recvfrom with "failing" sendto before.
// fixed: This should block.
// unfixed: WSAGetLastError is 10054
memset(rcvBuf, 0, sizeof(rcvBuf));
status = recvfrom(clientSock, rcvBuf, sizeof(rcvBuf), 0, (sockaddr*)&serverAddr, &sizeServerAddr);
lasterror = WSAGetLastError();
printf("recvfrom return %d (lasterror %d)\n", status, lasterror);
printf("--->From the server: -%s-\n", rcvBuf);
closesocket(clientSock);
}
int _tmain(int argc, _TCHAR* argv[])
{
/* Initializing WSA */
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
printf("##### UNFIXED\n");
testCase(false);
printf("##### FIXED\n");
testCase(true);
WSACleanup();
// pause
char buf[100];
gets(buf);
return 0;
}
This should return:
##### UNFIXED
Send to nowhere--->:
sendto return 7 (lasterror 0)
recvfrom return -1 (lasterror 10054)
--->From the server: --
##### FIXED
Send to nowhere--->:
sendto return 7 (lasterror 0)
and then block.

Winsock2: "listen" returns early

I'm new to using winsock2 and have put together the following code for a server that I'm trying to use to send a string to a client that I'm running on the same computer (connecting to 127.0.0.1 with the same port as the server is set to listen on).
I'm using MinGW, if that matters.
The problem I'm having is that listen() seems to finish early but returning a success code. This is a problem because then when accept() is called it seems to block forever. This event happens whether or not I am running the client program, and I have tried running the client program before and after but this doesn't seem to affect it.
// -1: "Could not initialize WSA."
// -2: "Could not create listener socket."
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <cstdio>
#define port 0x0ABC
UINT64 trStrLen (char* str)
{
if (str == NULL) return 0;
UINT64 pos = 0;
while (*(str + pos) != '\0') pos++;
return pos;
};
#include <cstdio>
int main ()
{
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2,0),&wsadata)) return -1;
SOCKET server = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
SOCKADDR_IN sin;
memset(&sin,0,sizeof(SOCKADDR_IN));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = INADDR_ANY;
int socksize = sizeof(SOCKADDR);
while (bind(server,(SOCKADDR*)(&sin),socksize) == SOCKET_ERROR) return -2;
char* TEMP_TO_SEND = "Billy Mays does not approve.";
UINT64 TEMP_SEND_LEN = trStrLen(TEMP_TO_SEND);
printf("Server online.\n");
while (true)
{
printf("Waiting for connections.\n");
while (listen(server,SOMAXCONN) == SOCKET_ERROR);
printf("Client requesting connection.\n");
SOCKET client = accept(server,NULL,NULL);
printf("Accept is no longer blocking.\n");
if (client != INVALID_SOCKET)
{
printf("Attempting to send information to the client...\n");
if (send(client,TEMP_TO_SEND,TEMP_SEND_LEN,0) == SOCKET_ERROR) printf("The information wasn't sent properly.\n");
else printf("The client received the information.\n");
}
else printf("Couldn't establish a connection to the client.\n");
};
};
It's probably something obvious, but I'm not seeing it, so any tips would be helpful.
listen() isn't a blocking call. It doesn't do anything to the network. It just puts the socket into passive listening mode, sets up the backlog queue, and returns. It is accept() that is the blocking call: it blocks until an incoming connection has been completed and then returns a socket for it.
So you shouldn't be calling listen() in a while loop at all.
Same applies to bind(). Call it once.

Stopping a receiver thread that blocks on recv()

I have a chat application that has a separate thread to listen for incoming messages.
while (main thread not calling for receiver to quit) {
string message = tcpCon.tcpReceive(); // Relies on the recv() function
processIncomingMessage(message);
}
This way of working has one big problem. Most of the time, the loop will be blocking on recv() so the receiver thread won't quit. What would be a proper way to tackle this issue without forcing thread termination after a couple of seconds?
Close the socket with shutdown() to close it for all receivers.
This prints out 'recv returned 0' on my system, indicating that the receiver saw an orderly shutdown. Comment out shutdown() and watch it hang forever.
Longer term, OP should fix the design, either using select or including an explicit quit message in the protocol.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
/* Free on my system. YMMV */
int port = 7777;
int cd;
void *f(void *arg)
{
/* Hack: proper code would synchronize here */
sleep(1);
/* This works: */
shutdown(cd, SHUT_RDWR);
close(cd);
return 0;
}
int main(void)
{
/* Create a fake server which sends nothing */
int sd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sa = { 0 };
const int on = 1;
char buf;
pthread_t thread;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(port);
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
/* Other error reporting omitted for clarity */
if (bind(sd, (const struct sockaddr*)&sa, sizeof sa) < 0) {
perror("bind");
return EXIT_FAILURE;
}
/* Create a client */
listen(sd, 1);
cd = socket(AF_INET, SOCK_STREAM, 0);
connect(cd, (const struct sockaddr*)&sa, sizeof sa);
accept(sd, 0, 0);
/* Try to close socket on another thread */
pthread_create(&thread, 0, f, 0);
printf("recv returned %d\n", recv(cd, &buf, 1, 0));
pthread_join(thread, 0);
return 0;
}
You could use select() to wait for incoming data and avoid blocking in recv(). select() will also block, but you can have it time out after a set interval so that the while loop can continue and check for signals to quit from the main thread:
while (main thread not calling for receiver to quit) {
if (tcpCon.hasData(500)) { // Relies on select() to determine that data is
// available; times out after 500 milliseconds
string message = tcpCon.tcpReceive(); // Relies on the recv() function
processIncomingMessage(message);
}
}
If you close the socket in another thread, then recv() will exit.
calling close on the socket from any other thread will make the recv call fail instantly.

OPENSSL with c++ and posix

I have a quick question. I set this client up as a sort of example, so I do not do a lot of extra work with it; I wanted to get the basic idea working first. I have it working so far, with one exception:
If I start it up, I can see the data being sent across on the other side (I use python+twisted). I can write with no problems, the problem comes when I read. On the server side, I am able to see the text coming in and being sent back out again. But on the client side, things are delayed. I have to send three commands to see something coming out.
for example:
I send hello <newline> cruel <newline> world<newline> and get hello echoed back to me, only after I hit enter on world.
Could someone point out why or give me some hints?
Here is the code.
#include <openssl/ssl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <cstdio>
//used for printing an error and then exiting.
inline void error(const char* message)
{
fprintf(stderr, "%s\n", message);
exit(EXIT_FAILURE);
}
//the buffer size we will be working with:
#define MAX_BUFF 4096
int main()
{
int ret; //used for holding bytes read.
int flag = 1; //our IOCTL flag.
char buff[MAX_BUFF]; //a buffer for holding i/o data.
fd_set rdesc, wdesc, srset, swset; //file descriptor sets.
timeval tv; //used for holding the time select should wait.
SSL_CTX* context = NULL; //ssl context.
SSL* ssl = NULL; //main ssl object.
sockaddr_in addr; //server socket address.
int sock = 0;
//clean out the struct:
bzero(&addr, sizeof(sockaddr_in));
//then fill it in.
addr.sin_family = AF_INET;
addr.sin_port = htons(4000);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr);
//create the socket
sock=socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
error("Error creating initial socket.");
}
//initialize SSL.
SSL_load_error_strings();
SSL_library_init();
//create the ssl context
context = SSL_CTX_new(TLSv1_client_method());
if (!context)
{
error("Could not create SSL context.");
}
//connect the socket to the server.
if (connect(sock, (sockaddr*)&addr, sizeof(sockaddr_in)) < 0)
{
error("Could not connect to specified socket.");
}
//create the ssl object.
ssl = SSL_new(context);
if (!ssl)
{
error("Could not create ssl object.");
}
//try to set the socket as the fd for the ssl object.
if (!SSL_set_fd(ssl, sock))
{
error("Error, could not bind fd to the ssl object.");
}
//link ssl up with the socket.
if (!SSL_connect(ssl))
{
error("Could not perform ssl handshake.");
}
ioctl(sock, FIONBIO, &flag);
//set our file descriptor sets.
FD_SET(fileno(stdin), &wdesc);
FD_SET(sock, &rdesc);
//wait for data, read, then print.
while (1)
{
//we need to zero out our i/o buffer.
bzero(buff, MAX_BUFF);
//initialize our temp fd sets.
srset = rdesc;
swset = wdesc;
//each time select finishes it changes this to how much time it actually slept, so we need to reset it.
tv.tv_usec = 50*1000; //50 ms
tv.tv_sec = 0;
//perform the actual select operation.
select(sock+1, &srset, &swset, NULL, &tv);
//check to see if data was written on stdin (user input)
if (FD_ISSET(fileno(stdin), &swset))
{
//read inputted data.
ret = read(fileno(stdin), buff, MAX_BUFF);
if (ret)
{
//write it to the socket.
SSL_write(ssl, buff, ret);
}
}
//check to see if we received anything.
if (FD_ISSET(sock, &srset))
{
printf("in if.\n");
//read it
ret = SSL_read(ssl, buff, MAX_BUFF);
printf("%d\n", ret);
if (ret)
{
//write it to screen.
printf("%s\n", buff);
}
}
}
return 0;
}