Unix socket loops - c++

I'm trying to implement a pair server/client programs that is able to exchange information through Unix Sockets. Problem is the client is constantly being reset and re-run by the server in a loop, and I'm having trouble sending/receiving data to and from the socket after the first time. Right now I have something like this:
Server:
int main(int argc, char const *argv[]){
unix_socket server;
server.initSocket(DEFAULT_SOCKET_PATH,SERVER_MODE);
server.wait();
bool first=true;
for (int i = 0; i < 30; ++i)
{
//send & receive data
server.closeSocket();
first=false;
}
return 0;
}
Client:
int loop_controller(){
unix_socket client;
client.initSocket(DEFAULT_SOCKET_PATH,CLIENT_MODE);
// receive & send data
client.closeSocket();
}
int main () {
for (int i = 0; i < 30; ++i){
loop_controller();
}
return 0;
}
The initSocket(), wait() and closeSocket() members of unix_socket class (mode 0 for servers, mode 1 for clients):
void unix_socket::initSocket(const char* sock_path, const int sc_mode){
if (sc_mode==0){
if (mode != sc_mode) mode=sc_mode;
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
//exit(1);
}
// ---
local.sun_family = AF_UNIX;
strcpy(local.sun_path, sock_path);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(sock, (struct sockaddr *)&local, len) == -1) {
close(sock);
perror("bind");
//exit(1);
}
// ---
} else if(sc_mode==1) {
if (mode != sc_mode) mode=sc_mode;
if ((client_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
//exit(1);
}
// ---
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, sock_path);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(client_sock, (struct sockaddr *)&remote, len) == -1) {
perror("connect");
//exit(1);
}
// ---
} else printf("Invalid sc_mode argument: %d\n",sc_mode);
}
//...
void unix_socket::wait(){
if (mode==0){
if (listen(sock, 5) == -1) {
perror("listen");
//exit(1);
}
t = sizeof(remote);
if ((client_sock = accept(sock, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
//exit(1);
}
} else printf("Invalid call to wait(): mode %d\n, must be 0",mode);
}
//...
void unix_socket::closeSocket(){
//close(sock);
close(client_sock);
}
//...
When running both programs with Valgrind, however, I'm getting SIGPIPE errors:
==5384==
==5384== Process terminating with default action of signal 13 (SIGPIPE)
==5384== at 0x573DDA2: send (send.c:28)
==5384== by 0x405910: unix_socket::sendMsg(char, double) (in .../server)
==5384== by 0x405B6C: unix_socket::sendVectorXd(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&) (in .../server)
==5384== by 0x402044: main (in .../server)
==5384==
I'm guessing that something is not being done correctly when closing/reopening socket. What would be the right procedure?

In your loop, you are only accept()ing once. The end of the loop body indicates the client socket being closed, but yet it is never accept()ed again for the next iteration.
Your loop should be something like:
server.startListening(); // bind, listen and friends
for (int i = 0; i < 30; i++) {
server.acceptClient(); // Call accept
// insert byte pushing routines here..
server.closeSocket(); // call close() on socket returned by accept()
}

Related

transfer files in a tcp threaded server C++

Hi everyone i have a little problem, i supposed to transfer a file from a server( a tcp server with threads to a client). The problems appers at the end of transmision the file is recived by client but it stucks and I can't longer communicate with it.
This is the server
int main(int argc, char *argv[])
{
int socket_desc, client_sock, c;
struct sockaddr_in server, client;
//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(2025);
//Bind
if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc, 5);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
int enable = 1;
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
pthread_t thread_id;
while ((client_sock = accept(socket_desc,
(struct sockaddr *) &client,
(socklen_t*) &c)))
{
puts("Connection accepted");
if (setsockopt(client_sock,
SOL_SOCKET,
SO_REUSEADDR,
&enable,
sizeof(int)) < 0)
error("setsockopt(SO_REUSEADDR) failed");
if (pthread_create(&thread_id,
NULL,
connection_handler,
(void*) &client_sock) < 0)
{
perror("could not create thread");
return 1;
}
//Now join the thread , so that we dont terminate before the thread
pthread_join(thread_id, NULL);
puts("Handler assigned");
}
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
return 0;
}
void *connection_handler(void *socket_desc)
{
printf("Enter in handler");
//Get the socket descriptor
int sock = *(int*) socket_desc;
send_problemo(sock);
return 0;
}
This is the sending function where I think is the real problem
int send_problemo(int *sock)
{
ssize_t read_return;
char *file_path = "Problems/1.txt";
char buffer[BUFSIZ];
int filefd;
filefd = open(file_path, O_RDONLY);
char end[2] = "1";
if (filefd == -1)
{
perror("open");
exit (EXIT_FAILURE);
}
while (1)
{
read_return = read(filefd, buffer, BUFSIZ);
if (read_return == 0)
{
printf("este 0 \n");
break;
}
if (read_return == -1)
{
perror("read");
exit (EXIT_FAILURE);
}
if (write(sock, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
}
// close(sock);
close(filefd);
}
The client is connecting normally and receives the file in this function
int recive_problemo(int *sockfd)
{
char *file_path = "path.c";
char buffer[BUFSIZ];
ssize_t read_return;
int filefd;
filefd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (filefd == -1)
{
perror("open");
exit (EXIT_FAILURE);
}
do
{
read_return = read(sockfd, buffer, BUFSIZ);
if (read_return == -1)
{
perror("read");
exit (EXIT_FAILURE);
}
if (write(filefd, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
} while (read_return > 0);
close(filefd);
}
I kind of managed how to solve this. If i shutdown(SHUT_WR) from server the client isnt stuck anymore, but i want to communicate with it further.
Also with the same function if i transfer from client to server, it works perfectly, so can anyone help me please?
do
{
read_return = read(sockfd, buffer, BUFSIZ);
// error handling
// file write
} while (read_return > 0);
Will keep looping until the socket closes or there's an error. It has no way to tell if a file has finished.
Common solutions are to close the socket (but you don't want that) and establish a communication protocol so that you know when the file is done and can exit the loop.
To keep things very simple, I recommend sending the length of the file before sending the file. The loop now looks something like:
uint64_t file_len;
read_return = recv(sockfd, &file_len, sizeof(file_len), MSG_WAITALL);
if (read_return == sizeof(file_len))
{
// Strongly consider handling the endian of file_len here
while (file_len)
{
size_t readmax = std::min(file_len, BUFSIZ);
read_return = read(sockfd, buffer, readmax);
if (read_return > 0)
{
if (write(filefd, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
file_len -= read_return;
}
else
{
// handle error
// exit loop if not recoverable
}
}
}
The server end picks up the responsibility of getting and sending the length of the file. I won't get into that because there are too many different ways to get the length of a file. Pick your favourite.
Documentation on recv and MSG_WAITALL.

HTTPS proxy never manages to connect successfully

What I'm trying to do is a forking proxy that deals HTTP(S) connections: while GET (without SSL) requests are successfully executed and the contents are delivered to the client, when it comes to CONNECT method things are not going well, since connect()ing to the remote server may not immediately succeeds: in fact, it nevers succeeds.
I tried for a non blocking socket connected to the remote server, so I can see if connect() goes immediately or takes some time: in the second case, I'd call select() to see when the remote server is ready to send data to me: yet, connect() never connects.
Here's my proxy main() code:
int main(int argc, char *argv[]) {
// ClientManager.cpp is described below
ClientManager cm;
//listening on port given by argv
if (cm.startListeningForClient(listening_port)) {
while(true) {
int new_client_socket = cm.acceptConnectionFromClient();
if (new_client_socket >= 0) {
cm.forkAndManageClient();
}
else {
perror("accept error");
}
}
} else {
perror("Error on start listening");
}
return EXIT_SUCCESS;
}
Now follows, with some omissis not involved with my issue, ClientManager.cpp, whose functions are called in main() above:
ClientManager::ClientManager() {
sockfd_client = -1; // socket connected to client
new_sockfd_client = -1; // socket accepting connection from client
sockfd_server = -1; // socket connected to remote server
}
// error controls omitted
bool ClientManager::startListeningForClient(int port) {
struct sockaddr_in serv_addr;
bzero((char*)&serv_addr,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(port);
serv_addr.sin_addr.s_addr=INADDR_ANY;
sockfd_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(sockfd_client,(struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(sockfd_client, 50);
return true;
}
// error controls omitted
int ClientManager::acceptConnectionFromClient(void) {
struct sockaddr_in cli_addr;
unsigned int clilen;
bzero((char*)&cli_addr, sizeof(cli_addr));
clilen = sizeof(cli_addr);
new_sockfd_client = accept(sockfd_client, (struct sockaddr*)&cli_addr, &clilen);
return new_sockfd_client;
}
int ClientManager::forkAndManageClient() {
// getRequestFromClient: the method below receives requests from
// clients and parses the infos I need (i.e. what method,
// hostname of remote server to be resolved, its port, ...)
getRequestFromClient();
// managing the HTTP(S) request by the child process
int pid = fork();
if (pid < 0) {
perror("ERROR on fork");
}
else if (pid > 0) {
// parent process
// do nothing
}
else {
// close immediately the client socket used for accepting new connections from the parent process
close (sockfd_client);
if (!manageRequest()) {
perror("Error managing request from client");
}
// close the connection from the client
close (new_sockfd_client);
new_sockfd_client = -1;
// the child process will terminate now
_exit(EXIT_SUCCESS);
}
return pid;
}
// now the problematic method...
bool ClientManager::manageRequest(void) {
// if this is a CONNECT request
if (rm.isCONNECT()) {
struct sockaddr_in remote_server;
int conn_res;
remote_server.sin_family = AF_INET;
remote_server.sin_addr.s_addr = rm.getServerAddr();
remote_server.sin_port = rm.getServerPort();
fd_set fdset;
struct timeval tv;
sockfd_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// make socket not blocking
int flags = fcntl(sockfd_server, F_GETFL, 0);
flags = flags | O_NONBLOCK;
if (fcntl(sockfd_server, F_SETFL, flags) == -1) {
perror("FCNTL:");
}
printf("CONNECT set socket to non-blocking mode\n");
conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in));
printf("AFTER CONNECT()\n");
if (conn_res < 0) {
if (errno != EINPROGRESS) {
printf("CONNECT: connect() failed, quitting\n");
return false;
}
}
printf("CONNECT connection is taking place...\n");
// connected immediately
if (conn_res == 0) {
printf("CONNECT connected OK!\n");
goto CONNECTED;
}
FD_ZERO(&fdset);
FD_SET(sockfd_server, &fdset);
tv.tv_sec = 5; // tried 5, 20, 60 seconds, but it always times out
tv.tv_usec = 0;
printf("CONNECT attempting select()\n");
if (select(sockfd_server+1, NULL, &fdset, NULL, &tv) == 0) {
errno = ETIMEDOUT;
close(sockfd_server);
sockfd_server = -1;
return false;
}
if (FD_ISSET(sockfd_server, &fdset)) {
int so_error;
socklen_t len = sizeof so_error;
if (getsockopt(sockfd_server, SOL_SOCKET, SO_ERROR, &so_error, &len) < 0) {
return false;
}
} else {
printf("sockfd_server not set\n");
}
CONNECTED:
fcntl(sockfd_server, F_SETFL, flags &~ O_NONBLOCK);
// yeah, now I will start to deal the HTTPS flow in both directions
return true;
}
}
It does manage setting socket to non blocking mode, and to print CONNECT connection is taking place..., but it always returns Error managing request from client: Connection timed out.
I apologize for posting miles of LOC, but this is what drives me crazy since days, and after reading posts, tutorial and guides, I really don't know what to do.
It connects now to every site which requires an HTTPS connection!
Proper error checking and following closing of socket descriptors were missing. Here's my code:
bool ClientManager::manageRequest(void) {
if (rm.isCONNECT()) {
struct sockaddr_in remote_server, local_bind;
int conn_res, select_res;
memset(&remote_server, 0, sizeof(remote_server));
remote_server.sin_family = AF_INET;
remote_server.sin_addr.s_addr = rm.getServerAddr();
remote_server.sin_port = rm.getServerPort();
memset(&local_bind, 0, sizeof(local_bind));
local_bind.sin_family = AF_INET;
local_bind.sin_addr.s_addr = htonl(INADDR_ANY);
local_bind.sin_port = htons(0);
fd_set rdset, wrset;
struct timeval tv;
sockfd_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd_server < 0) {
perror("socket: ");
}
if(!setNonBlocking(sockfd_server))
perror("fcntl");
debug_green("CONNECT set socket to non-blocking mode\n");
bind(sockfd_server, (struct sockaddr*) &local_bind, sizeof(local_bind));
conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in));
// The socket is nonblocking and the connection cannot be completed immediately
// check for EINPROGRESS
if ((conn_res == -1) && (errno != EINPROGRESS)) {
FD_ZERO(&rdset);
FD_SET(sockfd_server, &rdset);
wrset = rdset;
tv.tv_sec = 0;
tv.tv_usec = 0;
debug_yellow("CONNECT attempting select()\n");
do {
select_res = select(sockfd_server+1, &rdset, &wrset, NULL, &tv);
} while ((select_res == -1) && (errno == EINTR));
if ((!FD_ISSET(sockfd_server, &rdset)) && ((!FD_ISSET(sockfd_server, &wrset)))) {
debug_red("SELECT sockfds not responding\n");
close(sockfd_server);
sockfd_server = -1;
return false;
}
conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in));
if (conn_res == -1) {
if(errno == EISCONN)
printf ("connect(): connections already existing, OK\n");
else {
printf("connect() for safety check: connection NOT successfull\n");
close(sockfd_server);
sockfd_server = -1;
return false;
}
}
printf("connection OK\n");
fflush(stdout);
} else {
debug_green("Connection immediately OK\n");
fflush(stdout);
}
if (!setBlocking(sockfd_server)) {
perror("FCNTL:");
}
debug_green("CONNECT set socket back to blocking mode\n");fflush(stdout);
}
return true;
}
Functions setting blocking or non blocking socket:
bool ClientManager::setNonBlocking(int sockfd) {
printf("setting non block socket\n"); fflush(stdout);
int flags;
if ((flags = fcntl(sockfd, F_GETFL, 0)) < 0)
return false;
flags |= O_NONBLOCK;
if (fcntl(sockfd, F_SETFL, flags) < 0)
return false;
return true;
}
bool ClientManager::setBlocking(int sockfd) {
printf("setting block socket\n"); fflush(stdout);
int flags;
if ((flags = fcntl(sockfd, F_GETFL, 0)) < 0)
return false;
flags &= (~O_NONBLOCK);
if (fcntl(sockfd, F_SETFL, flags) < 0)
return false;
return true;
}
Debug functions:
#define DEFAULTCOLOR "\033[0m"
#define RED "\033[22;31m"
#define YELLOW "\033[1;33m"
#define GREEN "\033[0;0;32m"
#define debug_red(...) std::cout << RED << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout);
#define debug_yellow(...) std::cout << YELLOW << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout);
#define debug_green(...) std::cout << GREEN << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout);

Client socket connect() succeeds after server accept() times out

I'm working on a c++ class that acts as a high-level wrapper around sockets in linux. While testing it, I purposely made the server's accept() call time out by having the client application sleep for a few seconds before calling connect().
However, after the server times out, the client application is still able to call connect() and send data without detecting an error. This is obviously a problem, because the server is not receiving the data, so the client should know the connection failed.
Here is my code. The server app calls Socket::accept_connection() and the client app sleeps and then calls Socket::connect_to().
// Accept a connection on the server side with a timeout
Socket *Socket::accept_connection(double timeout) {
Socket *new_connection = NULL;
socklen_t sin_size;
struct sockaddr_storage client_address; // Client's address
struct sockaddr_in client_port_address; // Client's port
char s[INET6_ADDRSTRLEN];
sin_size = sizeof client_address;
fd_set rfds;
struct timeval timeout_structure;
timeout_structure.tv_sec = (long)(timeout);
timeout_structure.tv_usec = int((timeout - timeout_structure.tv_sec) * 1e6);
struct timeval *timeout_ptr = NULL;
if(timeout > 0)
timeout_ptr = &timeout_structure;
// Loop until the timeout has been reached
while(true) {
FD_ZERO(&rfds);
FD_SET(socket_desc, &rfds);
if(select(socket_desc + 1, &rfds, NULL, NULL, timeout_ptr) > 0) {
int client_sock = accept(socket_desc, (struct sockaddr *)&client_address, &sin_size);
if(client_sock == -1) {
// Failed to connect
connected = false;
continue;
} else {
// Connected
inet_ntop(client_address.ss_family, get_in_addr((struct sockaddr *)&client_address), s, sizeof s);
getpeername(client_sock, (struct sockaddr*)&client_port_address, &sin_size);
int client_port = ntohs(client_port_address.sin_port);
// ...
}
} else {
// Timed out
connected = false;
std::cout << "accept() timed out\n";
break;
}
}
return new_connection;
}
// Connect to the given ip address and port
bool Socket::connect_to(std::string server_ip, int server_port, double timeout) {
connected = false;
// Create the socket and allocate memory for reading in data
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
struct timeval timeout_structure;
timeout_structure.tv_sec = (long)(timeout);
timeout_structure.tv_usec = int((timeout - timeout_structure.tv_sec) * 1e6);
struct timeval *timeout_ptr = NULL;
if(timeout > 0)
timeout_ptr = &timeout_structure;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(server_ip.c_str(), std::to_string(server_port).c_str(), &hints, &servinfo)) != 0) {
fprintf(stderr, "Socket error: connect_to, getaddrinfo: %s\n", gai_strerror(rv));
throw;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((socket_desc = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("Socket error: connect_to, socket");
continue;
}
int flags = 0, error = 0, ret = 0;
fd_set rset, wset;
socklen_t len = sizeof(error);
//clear out descriptor sets for select
//add socket to the descriptor sets
FD_ZERO(&rset);
FD_SET(socket_desc, &rset);
wset = rset; //structure assignment ok
//set socket nonblocking flag
if((flags = fcntl(socket_desc, F_GETFL, 0)) < 0)
continue;
if(fcntl(socket_desc, F_SETFL, flags | O_NONBLOCK) < 0)
continue;
//initiate non-blocking connect
if(ret = connect(socket_desc, p->ai_addr, p->ai_addrlen) == -1) {
if (errno != EINPROGRESS) {
close(socket_desc);
perror("Socket error: connect_to, could not connect");
continue;
}
}
if(ret != 0) { // If connect did not succeed right away
// We are waiting for connect to complete now
if((ret = select(socket_desc + 1, NULL, &wset, NULL, timeout_ptr)) < 0)
return false;
if(ret == 0){ //we had a timeout
errno = ETIMEDOUT;
return false;
}
//we had a positive return so a descriptor is ready
if(FD_ISSET(socket_desc, &rset) || FD_ISSET(socket_desc, &wset)){
if(getsockopt(socket_desc, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error != 0)
return false;
} else
return false;
if(error){ //check if we had a socket error
errno = error;
return false;
}
}
//put socket back in blocking mode
if(fcntl(socket_desc, F_SETFL, flags) < 0)
return false;
break;
}
if(p == NULL) {
fprintf(stderr, "Socket error: connect_to, failed to connect\n");
socket_desc = 0;
return false;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s);
freeaddrinfo(servinfo); // all done with this structure
connected = true;
return connected;
}
This is normal, not a problem.
TCP maintains a listen backlog queue into which connections are placed that have been completed by the TCP stack but not yet accepted by the application.
TCP maintains a socket receive buffer per socket into which data is placed that has arrived from the peer and not yet been read by the application.
the client should know the connection failed.
It didn't fail. The server can accept it and read the data.

c++ winsock - server communicates only with single client while it should communicate with every client

I am writing a single chat program with GUI. I wanted to write a server that would accept many clients. Every client can connect successfuly. But there is a strange problem with sending and receiving data. I use select() and a thread to handle many sockets at the same time. If a client sends some data to server, it will receive it and send it back to that client (the client is especially written without "prediction"). But the server won't send it further to another clients (like every client had its own private conversation with the server). Here's my code:
// this is rewritten from the Beej's tutorial with a little and insignificant changes
/* in the thread */
fd_set mainfd;
fd_set readfd;
// sin-size, newfd, maxfd - int
while(TRUE)
{
readfd = mainfd;
if(select(maxfd+1, &readfd, NULL, NULL, NULL) == -1)
{
MessageBoxA(NULL, "Error while trying to accept incoming connections (select)", "Error", 16);
itoa(GetLastError(), buf, 10);
MessageBoxA(NULL, buf, buf, 0);
break;
}
for(int i = 0; i <= maxfd; i++)
{
char* psr;
char srMsg[256];
if(FD_ISSET(i, &readfd))
{
if(i == mainSocket)
{
sin_size = sizeof(their_addr);
newfd = accept(mainSocket, (struct sockaddr*)&their_addr, &sin_size);
if(newfd == SOCKET_ERROR)
{
AddTextToEdit(hStaticChat, "* Error: couldn't accept incoming connection.", TRUE);
}
else
{
FD_SET(newfd, &mainfd);
if(newfd > maxfd)
{
maxfd = newfd;
}
}
}
else
{
len = recv(i, srMsg, 256, 0);
if(len == 0 || len == SOCKET_ERROR)
{
AddTextToEdit(hStaticChat, "* Client has disconnected", TRUE);
close(i);
FD_CLR(i, &mainfd);
}
else
{
AddTextToEdit(hStaticChat, srMsg, TRUE);
for(int j = 0; j <= maxfd; j++)
{
if(FD_ISSET(j, &readfd))
{
send(j, srMsg, len, 0);
}
}
}
}
}
}
}
You are only sending data to the clients whos fd is in readfd, that is, only to that one which just communicated to you. Try to test FD_ISSET(j, mainfd) instead.
This code is not valid under WinSock. Windows does not deal with sockets using integer file descriptors like other platforms do. Sockets are represented using actual kernel objects instead, so you can't use loop counters as socket handles and such. There is also API differences (closesocket() instead of close(), maxfd is ignored by select(), FD_XXX() expect SOCKET handles instead of int, etc).
On Windows, you need to use something more like this instead:
fd_set mainfd;
SOCKET newfd;
int sin_size;
...
while(TRUE)
{
fd_set readfd = mainfd;
if (select(0, &readfd, NULL, NULL, NULL) == SOCKET_ERROR)
{
itoa(WSAGetLastError(), buf, 10);
MessageBoxA(NULL, "Error while trying to accept incoming connections (select)", "Error", 16);
MessageBoxA(NULL, buf, buf, 0);
break;
}
for(int i = 0; i < readfd.fd_count; i++)
{
if (readfd.fd_array[i] == mainSocket)
{
sin_size = sizeof(their_addr);
newfd = accept(mainSocket, (struct sockaddr*)&their_addr, &sin_size);
if (newfd == INVALID_SOCKET)
{
AddTextToEdit(hStaticChat, "* Error: couldn't accept incoming connection.", TRUE);
}
else
{
// Note that fd_set can only hold FD_SETSIZE (64) sockets as a time!
FD_SET(newfd, &mainfd);
}
}
else
{
char srMsg[257];
len = recv(readfd.fd_array[i], srMsg, 256, 0);
if (len < 1)
{
if (len == 0)
AddTextToEdit(hStaticChat, "* Client has disconnected", TRUE);
else
AddTextToEdit(hStaticChat, "* Error: couldn't read from a client connection.", TRUE);
closesocket(readfd.fd_array[i]);
FD_CLR(readfd.fd_array[i], &mainfd);
}
else
{
srMsg[len] = 0;
AddTextToEdit(hStaticChat, srMsg, TRUE);
for (int j = 0; j < mainfd.fd_count; j++)
{
if (mainfd.fd_array[i] != mainSocket)
send(mainfd.fd_array[j], srMsg, len, 0);
}
}
}
}
}

Reading socket: EAGAIN: Resource temporarily unavailable

I have created a socket in C++ and I needed it to have certain connection timeout. So that's what is happening:
Create socket
Make it NON_BLOCKING
Call connect
It returns -1 and errno EINPROGRESS as expected
Call select
Returns >0, so connection has been made
Make the socket BLOCKING again
Code for this part is the following:
bool mastControl::prepareSocket(char * address, int port, int * sockfd) {
struct sockaddr_in serv_addr;
struct timeval timeout = {0,100000};
struct timeval connTimeout;
struct hostent * server = NULL;
fd_set socketSet;
socklen_t lon;
int sockOpt = 0;
long socketFlags = 0;
int buffersize = 8;
int res = 0;
int connectReturn = 0;
const int WAIT_TO_RECONN = 15;
server = gethostbyname(address);
*sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (*sockfd < 0) {
qDebug()<<"Impossible to open socket: "<<strerror(errno);
return false;
}
if (server == NULL) {
qDebug()<<"No such host: "<<strerror(h_errno);
return false;
}
// Initializating server direction struct:
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(port);
// Making socked non-blocking in order to set a timeout value for connection:
if((socketFlags = fcntl(*sockfd, F_GETFL, NULL)) < 0){
qDebug()<<"Impossible to retrieve sockets descriptor flags "<<strerror(errno);
return false;
}
socketFlags |= O_NONBLOCK;
if(fcntl(*sockfd, F_SETFL, socketFlags) <0){
qDebug()<<"Impossible to update sockets descriptor flags: "<<strerror(errno);
return false;
}
connectReturn = connect(*sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr));
if(connectReturn < 0){
if(errno == EINPROGRESS){
do{
// Establishing a 15 seconds timeout:
connTimeout.tv_sec = 15;
connTimeout.tv_usec = 0;
FD_ZERO(&socketSet); // Initialising set of sockets as an empty set
FD_SET(*sockfd, &socketSet); // Adding socket to set
connectReturn = select(*sockfd+1, NULL, &socketSet, NULL, &connTimeout);
if(connectReturn<0 && errno!=EINTR){ // Error in select
qDebug()<<"Connection error in select function: "<<strerror(errno);
return false;
}
else if(connectReturn>0){ // Socket selected for writing
lon = sizeof(int);
if(getsockopt(*sockfd, SOL_SOCKET, SO_ERROR, (void*)(&sockOpt), &lon) <0){
qDebug()<<"Unnable to get socket options: "<<strerror(errno);
return false;
}
// Checking the value returned:
if(sockOpt){
qDebug()<<"Error in delayed connection: "<<strerror(errno);
return false;
}
break;
}
else{ // Timeout
qDebug()<<"Connection timeout exceeded: "<<strerror(errno);
return false;
}
} while (1);
}
else{
qDebug()<<"Connection error: "<<strerror(errno);
sleep(WAIT_TO_RECONN); // Wait 15 seconds
return false;
}
}
//Connected
// Must set the socket as blocking again:
if((socketFlags = fcntl(*sockfd, F_GETFL, NULL)) < 0){
qDebug()<<"Impossible to retrieve sockets descriptor flags "<<strerror(errno);
return false;
}
socketFlags &= (~O_NONBLOCK);
if(fcntl(*sockfd, F_SETFL, socketFlags) <0){
qDebug()<<"Impossible to update sockets descriptor flags "<<strerror(errno);
return false;
}
if (setsockopt (*sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof(timeout)) < 0) {
qDebug()<< "ERR - setsockopt failed";
return false;
}
if (setsockopt (*sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
sizeof(timeout)) < 0) {
qDebug()<< "ERR - setsockopt failed";
return false;
}
if ((res = setsockopt (*sockfd, SOL_SOCKET, SO_SNDBUF, &buffersize,
sizeof(buffersize))) == -1) {
qDebug()<< "ERR - setsockopt failed (SO_SNDBUF) = " << res;
return false;
}
//Socket Ready
return true;
}
That works ok. But then I have a loop where I'm calling a function which checks if there is a new packet received to read:
bool mastControl::findPacket(int sockfd, st_messageMastToPc * messageReceived, bool * connected) {
int n = 0;
bool messageFound = false;
char * buffer = (char *) messageReceived;
unsigned int pos = 0;
while ( ((n = read(sockfd, &(buffer[pos]), 1)) > 0) and not messageFound) {
//qDebug() << "read output " << n;
if (n == 1) {
pos++;
if ( (pos == 1) && (buffer[0] == 2)) {
// Some stuff...
} else if ( (pos == 2) && (buffer[1] == 2) ) {
// Some stuff...
} else if (pos >= uiMessageMastToPcSize) {
messageFound = true;
//Complete message received
} else if (pos < 2) {
// Reseting pos
pos = 0;
}
}
}
if (n < 0){
qDebug()<< "Disconnected. Reason #" << errno << ": " << strerror(errno);
*connected = false;
}
return messageFound;
}
Read function is giving EAGAIN as errno, which means "Resource temporarily unavailable". Then I'm supposing I am disconnected, and since boolean connected is now false, in the loop I will be trying to reconnect creating the socket again, ans so on.
So, in the first place I don't know why I'm receiving this error.
In the second place, I don't know if I am disconnected at all, or it's me the one who is disconnecting when creating the new socket after this error.
Any help?
EAGAIN does not mean you're disconnected, it just means "there's nothing to read now; try again later".
You could either unset O_NONBLOCK with fcntl(2) (making read wait until there's something available), or just wait on the socket with something like select(2) before calling read.
EDIT: Now that you've added more code, I can see that you're setting SO_RCVTIMEO for the socket. This can cause a blocking read to return EAGAIN (so if you don't want that to happen, simply leave SO_RCVTIMEO alone).