I am facing one of the strangest programming problems in my life. I've built a few servers in the past and the clients would connect normally, without any problems.
Now I'm creating one which is basically a web server. However, I'm facing a VERY strange situation (at least to me).
Suppose that you connect to localhost:8080 and that accept() accepts your connection and then the code will process your request in a separate thread (the idea is to have multiple forks and threads across each child - that's implemented on another file temporarily but I'm facing this issue on that setup as well so...better make it simple first). So your request gets processed but then after being processed and the socket being closed AND you see the output on your browser, accept() accepts a connection again - but no one connects of course because only one connection was created.
errno = 0 (Success) after recv (that's where the program blows up) recv returns 0 though - so no bytes read (of course, because the connection was not supposed to exist)
int main(int argc, char * argv[]){
int sock;
int fd_list[2];
int fork_id;
/* Socket */
sock=create_socket(PORT);
int i, active_n=0;
pthread_t tvec;
char address[BUFFSIZE];
thread_buffer t_buffer;
int msgsock;
conf = read_config("./www.config");
if(conf == NULL)
{
conf = (config*)malloc(sizeof(config));
if(conf == NULL)
{
perror("\nError allocating configuration:");
exit(-1);
}
// Set defaults
sprintf(conf->httpdocs, DOCUMENT_ROOT);
sprintf(conf->cgibin, CGI_ROOT);
}
while(cicle) {
printf("\tWaiting for connections\n");
// Waits for a client
msgsock = wait_connection(sock, address);
printf("\nSocket: %d\n", msgsock);
t_buffer.msg = &address;
t_buffer.sock = msgsock;
t_buffer.conf = conf;
/* Send socket to thread */
if (pthread_create(&tvec, NULL, thread_func, (void*)&t_buffer) != 0)
{
perror("Error creating thread: ");
exit(-1);
}
}
free(conf);
return 0;
}
Here are two important functions used:
int create_socket(int port) {
struct sockaddr_in server, remote;
char buffer[BUFF];
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_in))) {
perror("binding stream socket");
exit(1);
}
gethostname(buffer, BUFF);
printf("\n\tServidor a espera de ligações.\n");
printf("\tUse o endereço %s:%d\n\n", buffer,port);
if (listen(sock, MAXPENDING) < 0) {
perror("Impossível criar o socket. O servidor vai sair.\n");
exit(1);
}
return(sock);
}
int wait_connection(int serversock, char *remote_address){
int clientlen;
int clientsock;
struct sockaddr_in echoclient;
clientlen = sizeof(echoclient);
/* Wait for client connection */
if ((clientsock = accept(serversock, (struct sockaddr *) &echoclient, &clientlen)) < 0)
{
perror("Impossivel estabelecer ligacao ao cliente. O servidor vai sair.\n");
exit(-1);
}
printf("\n11111111111111Received request - %d\n", clientsock);
sprintf(remote_address, "%s", inet_ntoa(echoclient.sin_addr));
return clientsock;
}
So basically you'd see: 11111111111111Received request - D
D is different both times so the fd is different definitely.
Twice! One after the other has been processed and then it blows up after recv in the thread function. Some times it takes a bit for the second to be processed and show but it does after a few seconds. Now, this doesn't always happen. Some times it does, some times it doesn't.
It's so weird...
I've rolled out the possibility of being an addon causing it to reconnect or something because Apache's ab tool causes the same issue after a few requests.
I'd like to note that even if I Don't run a thread for the client and simply close the socket, it happens as well! I've considered the possibility of the headers not being fully read and therefore the browsers sends another request. But the browser receives the data back properly otherwise it wouldn't show the result fine and if it shows the result fine, the connection must have been closed well - otherwise a connection reset should appear.
Any tips? I appreciate your help.
EDIT: If I take out the start thread part of the code, sometimes the connection is accepted 4, 5, 6 times...
EDIT 2: Note that I know that the program blows up after recv failing, I exit on purpose.