TheMangaStand TheMangaStand - 1 month ago 6
C Question

C Thread Http Server Error

I am practicing different forms of causing a server to run concurrently by being able to accept multiple responses from multiple clients. This is a school assignment.

I am now having troubles with threading. The thread works but gets an error of

"curl: (56) Recv failure: Connection reset by peer"

This is because of the line in the response function that my thread goes to. Rest assured all variables besides clients[n] are pretty much constants. So its rather not passing in right or I'm completely missing the mark on how threading should be done.

rcvd = recv(clients[n], mesg, 99999, 0);


which this line keeps returning -1 into rcvd and I want > 0.

Here is my code.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<signal.h>
#include<fcntl.h>
#include<pthread.h>

#include "functions.h"
#define CONNMAX 1000
#define BYTES 1024

char *ROOT;
int verbose;
int signalReceived = 1;
int listenfd, clients[CONNMAX], slot;
pthread_t thread;
void error(char *);

void *threadServer(void *arg)
{
printf("bong");
respond(slot, verbose, ROOT, clients);
exit(0);
}

void clean(int arg)
{
signalReceived = 0;
}

int main(int argc, char *argv[])
{

signal(SIGINT, clean);
signal(SIGHUP, clean);

struct sockaddr_in clientaddr;
socklen_t addrlen;
char c;
char PORT[6];
ROOT = getenv("PWD");
strcpy(PORT, "8888");
while ((c = getopt (argc, argv, "p:v")) != -1)

switch (c)
{
case'v':
verbose = 1;
break;

case'p':
strcpy(PORT, optarg);
break;

case'?':
fprintf(stderr, "Wrong arguments given\n");
exit(1);

default:
exit(1);
}
printf("Listening on port %s%s%s, root is %s%s%s\n", "\033[92m", PORT, "\033[0m", "\033[92m", ROOT, "\033[0m");
int i = 0;
for (i = 0; i < CONNMAX; i++)
clients[i] = -1;
startServer(PORT, &listenfd);

while (signalReceived == 1)
{
addrlen = sizeof(clientaddr);
clients[slot] = accept (listenfd, (struct sockaddr *) &clientaddr, &addrlen);

if (clients[slot] < 0)
exit(0);

else
{
printf("bang");
pthread_create(&thread, NULL, threadServer, NULL);
}
while (clients[slot] != -1)
slot = (slot + 1) % CONNMAX;
}
return 0;
}


I am learning and this is not my original source work, rather an edited work in order to learn. I took a forked original program and am now trying to convert it to a threaded program.

Answer

slot is a global variable. Starting a thread can take a little while, and threads share the same memory. They don't have their own snapshots of it like a forked process does.

After starting the thread, your main process alters slot.

Best case scenario: new thread starts and gets the new value of slot such that connections[slot] == -1. Worst case: the thread runs on a different CPU core and gets slot while main is writing to it, resulting in a bad value.

You might want to consider passing slot as a parameter to the thread function instead:

void *threadServer(void *arg)
{
    int mySlot = (int)arg;
    printf("bong\n");
    respond(mySlot, verbose, ROOT, clients);
    clients[mySlot] = -1;
    printf("bash\n");
    return NULL;  // calling 'exit' terminates the whole process. duh.
}

// ...

    pthread_create(&thread, NULL, threadServer, (void*)slot);

Another issue you have here is that you create all these threads but you do not keep track of them individually. You probably need an array of threads, or you might want to consider a simple struct:

typedef struct Clients {
    int fd;
    pthread_t thread;
} Clients;
Clients clients[MAXCONN];

//

while (signalReceived == 1)
{
    addrlen = sizeof(clientaddr);
    clients[slot].fd = accept(listenfd, (struct sockaddr *) &clientaddr, &addrlen);

    if (clients[slot].fd < 0)
        exit(0);
    else
    {
        printf("bang");
        pthread_create(&clients[slot].thread, NULL, threadServer, (void*)slot);
    }

    while (clients[slot] != -1)
        slot = (slot + 1) % CONNMAX;  // what if we can't find one?
}