I'm having a segmentation fault problem with a networking program using threads to deal with each new connection.
MAX_PEERS is defined above as 10.
...
int iret[MAX_PEERS];
pthread_t thread[MAX_PEERS];
(void) signal(SIGCHLD, reaper);
printf("before while\n");
int i = 0;
while(1) {
if(i>MAX_PEERS-1){break;}
client_len = sizeof(client);
new_sd = accept(sd, (struct sockaddr *)&client, &client_len);
if(new_sd < 0){
fprintf(stderr, "Can't accept client \n");
exit(1);
}
printf("before thread\n");
iret[i] = pthread_create(&thread[i], NULL, connection, (void*) new_sd);
if(iret != 0){
printf("thread[%d] not generated!\n", i);
}
i++;
printf("end of while\n");
}
....
and the function "connection" beggins as follows
void *connection(void *sdd)
{
int sd =* (int *) sdd;
...
When the client tries to connect to the server I get a segmentation fault.
> ./server 20011
before while
before accept
after accept
before thread
./server: zsh: segmentation fault ./server 20011
>
It prints "before accept" before the client connects, and after the client connects it prints the rest.
Am I creating the threads correctly? Any ideas?
Thanks,
accept() returns an integer, so new_sd must be an integer. When you create a new thread you cast new_sd to a void pointer. But when you get that pointer in the function, instead of casting back to int you cast it to a pointer to int and dereference it, which causes the seg fault.
Instead of using possibly incorrect casting, rather pass an integer. Assuming that new_sd will go out of scope, allocate space for an integer and pass it to your thread.
int* new_sdp = malloc( sizeof( *new_sdp )) ;
*new_sdp = new_sd ;
iret[i] = pthread_create(&thread[i], NULL, connection, new_sdp);
and in the thread:
void *connection(void *sdd)
{
int sd = *(int *)sdd;
Related
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.
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?
}
Your threadServer function calls exit, terminating the process.
I'm not sure where that came from, since it wouldn't be appropriate in a server that calls fork either. But it's definitely fatal in a multi-threaded program.
I have the following code serving as main loop for a server that accepts incoming socket connections.
At the moment the macro OperationMode is defined as 1 so it will execute the pthread logic.
for (hit = 1 ;; hit++) {
printf("Got here\n\n");
length = sizeof(cli_addr);
/* block waiting for clients */
socketfd = accept(listenfd, (struct sockaddr *) &cli_addr, &length);
if (socketfd < 0)
printf("ERROR system call - accept error\n");
else
{
printf("Testing\n\n\n");
#ifdef OperationMode
pthread_t thread_id;
if(pthread_create(&thread_id, NULL, attendFTP(socketfd, hit), NULL))
{
perror("could not create thread");
return 1;
}
#else
pid = fork();
if(pid==0)
{
ftp(socketfd, hit);
}
else
{
close(socketfd);
kill(pid, SIGCHLD);
}
#endif
}
}
I'm able to create a thread for the first incoming socket connection but once I iterate over the loop I get segmentation fault error in the line
socketfd = accept(listened, (struct sockaddr *) &cli_addr, &length);
My attendFTP function has the following code
void *attendFTP(int fd, int hit)
{
ftp(fd, hit);
return NULL;
}
This works perfect for the fork implementation. How can I fix the segmentation fault error?
pthread_create(&thread_id, NULL, attendFTP(socketfd, hit), NULL);
This code passess result of a call to attendFTP() with given paramters - and this result is always NULL.
So pthread_create is trying to launch a function at NULL address and, correspondingly, fails.
If you run your compiler with -pedantic argument, compiler will tell you that what you are doing is wrong. Without -pedantic, gcc allows for some 'extensions', which might hide errors. Btw, this is why -pedantic is, in my view, a must.
What you actually want is to pass some arguments to your threading function. Unfortunately, it is really convoluted in C pthreads, and requires you to allocate and deallocate the said struct. Something like this:
struct args {
int fd;
int hit;
};
...
pthread_t thread_id;
struct args* args = malloc(sizeof(struct args));
args->fd = socketfd;
args->hit = hit;
if(pthread_create(&thread_id, NULL, attendFTP, args))
....
void* attendFTP(void* vargs)
{
struct args* args = vargs;
ftp(args->fd, args->hit);
free(args);
return NULL;
}
I am working on a multi-threaded server application.The server accepts connections from multiple devices and assign each connection a thread.The thread is a looping thread i.e it uses a while loop which iterates until the client closes the connection.
Currently when multiple clients got connected to the server only single client is able to communicate i.e the data sent by a single device is received at the server side and updated in database the other devices remain connected to server but no data is received from them. what seems the reason to me (not sure only assuming) is that only a single thread remains executing and other threads don't get the turn to execute.
so I want to schedule threads in round robin so that each thread executes.How can I schedule threads in round robin
I got the following code on-line but it was not able to schedule the threads in round robin.
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setschedpolicy(&attr, SCHED_RR);
Here is my code which creates threads:
connfd = accept(sock_desc, (struct sockaddr *)&echoClntAddr,(socklen_t*)&clntSock);
if(connfd > 0){
conn_desc = connfd;
puts("Connection accepted");
if(pthread_create( &thr, &attr , connection_handler , (void*)&conn_desc) < 0){
perror("could not create thread");
}
Your problem is not related to the scheduler policy. You have a potential race condition in your code.
// parent thread
while (1) {
listen(...);
connfd = accept(sock_desc, (struct sockaddr *)&echoClntAddr,
(socklen_t*) &clntSock);
conn_desc = connfd;
pthread_create(&thr,&attr,connection_handler,(void*) &conn_desc);
}
// child thread function
void *
connection_handler(void *ptr)
{
int fildes = *(int *) ptr;
...
return (void *) 0;
}
The race is that the parent can fire a second thread before the first thread has been able to dereference ptr. Thus, two threads will use the same value for connfd.
To correct this, we need to slightly modify the calling sequence to a pass-by-value:
// parent thread
while (1) {
listen(...);
connfd = accept(sock_desc, (struct sockaddr *)&echoClntAddr,
(socklen_t*) &clntSock);
pthread_create(&thr,&attr,connection_handler,(void*) connfd);
}
// child thread function
void *
connection_handler(void *ptr)
{
int fildes = (int) ptr;
...
return (void *) 0;
}
Side note: It is guaranteed that an int can be passed inside a pointer in this manner, but for sticklers, see below.
// parent thread
while (1) {
listen(...);
connfd = accept(sock_desc, (struct sockaddr *)&echoClntAddr,
(socklen_t*) &clntSock);
ptr = malloc(sizeof(int));
*ptr = connfd;
pthread_create(&thr,&attr,connection_handler,(void*) ptr);
}
// child thread function
void *
connection_handler(void *ptr)
{
int fildes = *(int *) ptr;
free(ptr);
...
return (void *) 0;
}
I need to do simple client program, when I add port number and client will be serch all services for this port. Now is problem with segmentation fault in if statement.
How to return all services? In my program it will be return just one, I think.
my code:
int main (int argc, char *argv[])
{
int sockfd, n,pol, s;
int numer;
char recvline[MAXLINE +1];
char p;
struct sockaddr_in servaddr;
struct servent *sp;
if (argc != 3)
err_sys("Aby uruchomić podaj: klient <Adres IP> <port>");
s = atoi(argv[2]);
if((sp = getservbyport(s,NULL)) == NULL)
{
printf("port (s): %d \n", s);
printf("port (sp): %d \n", sp->s_port); //segmentation fault
err_sys("problem with port");
}
if((sockfd = socket(AF_INET, SOCK_STREAM, 0))<0)
err_sys("Blad utworzenia polaczenia");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = sp->s_port;
if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr)<=0)
err_sys_kom("Blad konwersji do adresu IP dla %s", argv[1]);
printf("%s", sp->s_name);
pol = connect(sockfd, (SA*) &servaddr, sizeof(servaddr));
if (pol < 0)
{
err_sys_kom("Blad polaczenie z serwerem");
close(sockfd);
exit(-1);
}
else
str_cli(stdin, sockfd , 1);
exit(0);
}
EDIT (in response to new new problem - see comments below):
You probably need to get a list of protocols and work with those in a loop. The contents of the loop should roughly be:
Call getprotoent
If the result is NULL, exit the loop.
Else, dig out the protocol name from the returned structure.
Use that name as the second argument for getservbyport
Do what you want to with the result
EDIT (in response to new problem):
if((sp = getservbyport(s,NULL)) == NULL)
So your logic is to read sp ONLY IF sp is NULL. Obviously it will segfault.
It should be:
if((sp = getservbyport(s,NULL)) != NULL)
But then you will point out another new problem:
Why is sp NULL?
This could be because (as per the earlier version of my answer), you did an atoi on something which was not an integer. It could be because of any other reason. We can't say because we don't know what input you give.
This following part of the answer was in response to an old problem that the OP asked in the same question, and has since then chosen to edit over it:
First of all: Since you're using getservbyport, you really should read about services, if you haven't already.
Now on to the error:
getservbyport is of type:
struct servent *getservbyport(int port, const char *proto);
You are passing argv[2] which is of type char * instead of an int for port.
I believe the user inputs this as an argument in your program?
If you know that a char * points to a set of characters which look like an integer, like "1024", then you can convert it to an integer with atoi.
Do this instead, on the line with the error, when calling getservbyport, while making sure you've included stdlib.h:
getservbyport(atoi(argv[2]),NULL)
If argv[2] is NOT representable as an integer, you'll get undefined behavior, so maybe, you'll want to check this first.
this is a simple program I've been working on that listens to a socket, and starts a new thread to handle each connection to said socket.
In my while loop I get a Segmentation Fault, that has something to do with pthread_create (if I comment that line out the program loops properly). My knowledge of pointers is mediocre at best, and debugging with gdb didn't yield anything of value. This is gdb's output:
#0 0x0000000000000000 in ?? ()
#1 0x000000080064f4f1 in pthread_getprio () from /lib/libthr.so.3
#2 0x0000000000000000 in ?? ()
Error accessing memory address 0x7fffffbff000: Bad address.
The program gets through the while loop once successfully, and properly receives and responds to a connection at the socket, but then before getting into the second while loop, the program fails on a Segmentation Fault error.
Here's a condensed version of my program:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <pthread.h>
#define UNIX_PATH_MAX 100
#define SOCK_PATH "/tmp/demo_socket"
/*===============> CONNECTION HANDLER FUNCTION <=================*/
void *connection_handler(int connection_fd)
{
int nbytes;
char buffer[256];
nbytes = read(connection_fd, buffer, 256);
buffer[nbytes] = 0;
printf("\tMESSAGE FROM CLIENT: %s\n", buffer);
nbytes = snprintf(buffer, 256, "Hello from the server!");
write(connection_fd, buffer, nbytes);
close(connection_fd);
return;
}
/*==========================> MAIN <=============================*/
int main(void)
{
struct sockaddr_un addr; //socket address information
int sock_fd, conn_fd; //socket file descriptors
socklen_t addr_len = sizeof(struct sockaddr_un); //size of sockaddr_un structure
pid_t child_pid; //pid holder
pthread_t thread; // thread identifier
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock_fd < 0)
return 1;
unlink(SOCK_PATH);
memset(&addr, 0, addr_len);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path) - 1); // Copies up to sizeof(addr.sun_path)-1 bytes from SOCK_PATH into addr.sun_path
printf("> Socket sun_family = %d (AF_UNIX), Socket sun_path = %s ...\n", addr.sun_family, addr.sun_path);
/*----------------------FAIL CHECKS-------------------------*/
if (bind(sock_fd, (struct sockaddr *) &addr, addr_len) != 0)
return 1;
if (listen(sock_fd, 5) != 0)
return 1;
printf("> Listening to socket bound at %s ...\n\n", SOCK_PATH);
/*--------------------WHILE LOOP----------------------------*/
while ( (conn_fd = accept(sock_fd, (struct sockaddr *) &addr, &addr_len)) > -1) {
pthread_create(&thread , NULL, connection_handler(conn_fd), NULL);
printf("> Closing connection at %d inside server process ...\n", conn_fd);
close(conn_fd);
printf("> Reached bottom of loop!\n");
}
/*---------------------------FIN------------------------------*/
close(sock_fd);
unlink(SOCK_PATH);
printf("> Socket closed and unlinked from path ... Done!\n ");
return 0;
}
Any help would be greatly appreciated!
This is wrong:
pthread_create(&thread , NULL, connection_handler(conn_fd), NULL);
pthread_create requires the address of the function to run in the new thread. What your code does is call connection_handler in the main thread and then pass the result of connection_handler to pthread_create as the function address.
What you need is the following:
pthread_create(&thread , NULL, connection_handler, (void*)conn_fd);
You'll also need to change connection_handler to take void* instead of int:
void *connection_handler(void* arg)
{
intptr_t connection_fd = (intptr_t)arg;
...
}
Your usage of pthread_create is incorrect. the third argument should be a pointer to a function of type void *(*start_routine) (void *), instead you are passing the return of connection_handler.
Change connection_handler to receive a void * argument (and make sure it returns an actual value), eg.
#include <stdint.h>
void *connection_handler(void *arg)
{
intptr_t connection_fd = (intptr_t)arg;
...
return NULL;
}
and change your call to something like the following
pthread_create(&thread, NULL, &connection_handler, (void *)conn_fd);
You should also make sure to either start the thread detached, detach the thread with pthread_detach or join it later with pthread_join
buffer[nbytes] = 0;
This will overflow if you've read 256 bytes. Increase buffer size or decrease read size by one.
Most likely because you are closing the socket connection in two places. There is good chance that in one run of the thread its not yet got around to the write but in your parent thread already closed the connection.
Why do you need to create so many threads? Wouldn't one worker thread suffice? you can pile up the jobs on to this worker thread...