I am creating a server daemon in c that accepts numerous simultaneous connections, and the clients will be sending data to the server. I currently have each client connection being spawned into a new thread. I am seeing that accept() will sometimes (not always) return the ID of existing connection which (obviously) causes a wide variety of issues, including segmentation faults.
I even turned off the socket option SO_REUSEADDR to make sure that wasn't the case. Whenever a single client makes numerous consecutive calls, everything is fine (conid in my code below increments - 5,6,7,8,9, etc...). But whenever more than one client ties to simultaneously connect, sometimes conid gets duplicated (an example from one run: 5,6,7,7,8,9,10,10,10,11,12,12, ...).
I'm wondering how accept() can return an existing connection?? It would make sense if I was calling accept() within more than one thread, but as you can see below it only exists in the main process thread. On the other hand, I never experienced this issue with select(), so maybe it is an issue with threading??? At this point, I've tried just about everything I can think of, but it's apparent to me I'm just missing something
Edit: edited code to show that mystruct wasn't being free'd in the while loop, and (hopefully) provide more insight.
Edit #2: per request, I have posted the full source of my example.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdarg.h>
#include <time.h>
#include <errno.h>
#include <netdb.h>
//this is my test structure
struct mystruct_ {
int id; //only id for testing
};
typedef struct mystruct_ mystruct;
//error logging function
void merr(const char *msg, ...) {
//get the time
time_t t;
time(&t);
//grab this function's arguments
va_list args;
char buf[BUFSIZ];
va_start(args,msg);
//build the message
vsprintf(buf,msg,args);
//output the message
printf(" ERROR :: %s\n",buf);
//that's it!
va_end(args);
}
//this function handles the threads
void *ThreadedFunction(void *arg) {
//get the passed structure
mystruct *test = (mystruct *)arg;
//print conid -- this is where I am seeing the duplicates
printf("my connection id is %d\n",test->id);
// do some stuff, like: pull vars out of mystruct
int nbytes;
char buf[256];
while(1) {
if((nbytes=recv(test->id, buf, sizeof buf, 0)) <= 0) {
//handle break in connection
close(test->id);
} else {
//for this example, just print out data from client to make my point
buf[nbytes] = 0;
printf("%s",buf);
}
}
}
//main just sets up the connections and creates threads
int main(int argc, char *argv[])
{
char *port = "1234";
//get ready for connection
struct sockaddr_storage addr;
socklen_t addrsize = sizeof addr;
struct addrinfo hints, *res, *ai, *p;
int sockfd, conid, rv;
int yes = 1;
//
//load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
if((rv = getaddrinfo(NULL, port, &hints, &ai))!= 0) {
merr("failed to bind port '%s': %s\n",port,gai_strerror(rv));
exit(1);
}
//
//bind the port
for(p=ai; p!=NULL; p=p->ai_next) {
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if(sockfd<0) continue;
//setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); //commented for testing
if(bind(sockfd,p->ai_addr,p->ai_addrlen)<0) { close(sockfd); continue; }
break;
}
//if we don't have p, it means server didn't get bound
if(p==NULL) { merr("failed to bind port '%s' (reason unknown)",port); exit(2); }
freeaddrinfo(ai); //all done with this
//
// listen to the (now bounded) socket:
if(listen(sockfd,10)==-1) { merr("listen; errmsg: \"%s\"",strerror(errno)); exit(3); }
// bind(), listen(), etc... blah blah blah
mystruct test[1024]; //just for testing
printf("Ready and Listening...\n");
while(1) {
conid = accept(sockfd, (struct sockaddr *)&addr, &addrsize);//get a connection
test[conid].id = conid;
pthread_t p;
pthread_create(&p,NULL,ThreadedFunction,&test[conid]); //create new thread
}
}
This is broken:
while(1) {
conid = accept(sockfd, (struct sockaddr *)&addr, &addrsize);//get a connection
test[conid].id = conid;
pthread_t p;
pthread_create(&p,NULL,ThreadedFunction,&test[conid]); //create new thread
}
pthread_t p; declares an opaque handle on the stack which pthread_create will fill in. That handle's lifetime must last until you call pthread_join or pthread_detach.
In this case, the storage for that pthread_t is probably being reused, messing up the passing of the argument to the thread function. At least, that is my guess.
Try calling pthread_detach after pthread_create.
accept returns a file descriptor that my be reused. As your ThreadedFunction never terminates when done with a file descriptor you will get a race condition. So after the close statement put return;
Related
I'm writing a simple quote server in C and running on Linux. It should pick a random quote from a text file and then start two threads:
the first is in charge of accepting incoming connections and respond with the selected quote,
the second should check once an hour if a day has passed. If it detects that a new day has started it should randomly pick another quote.
My problem is that while the connection thread works fine, the other doesn't even start.
To confirm this I've tried to add a debug print right at the start of the function executed by the thread and another inside it's while loop and none gets printed (those are removed from the code shown here).
I've also added some code to check the pthread_create() return value copied from it's man page but I'm unsure if it's actually working since it doesn't detect any error.
I've tied to first start the "timer thread" first and not start the connection thread at all but still it doesn't get executed. Here follows the relevant code, you can find the full source on GitHub:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#include <pthread.h>
#include <errno.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
pthread_mutex_t quoteLock=PTHREAD_MUTEX_INITIALIZER;
pthread_t checkForNewDayThread, connectionHandlerThread;
void * timer_thread_code(){ //The thread will act as a timer checking every hour if a day has passed
while (true) {
sleep(3600);
if (a_day_has_passed()) {
pthread_mutex_lock("eLock);
QOTD = read_random_quote_from_file(pathToQOTDfile);
pthread_mutex_unlock("eLock);
}
}
}
void * connection_thread_code(int port){ //Code for the thread to handle connections
struct sockaddr_in address;
int server_fd, new_socket, opt = 1, addrlen = sizeof(address);
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 1717
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))==-1)
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( port );
// Forcefully attaching socket to the port 1717
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 100) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
printf("Listening on port %i\n", port);
while(1) { //connection handler loop
if ((new_socket = accept(server_fd, (struct sockaddr *) &address, (socklen_t *) &addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
pthread_mutex_lock("eLock);
send(new_socket, QOTD, strlen(QOTD), 0);
pthread_mutex_unlock("eLock);
close(new_socket);
}
}
int main(int argc, char const *argv[])
{
int thread1, thread2, join;
thread1=pthread_create(&connectionHandlerThread, NULL, connection_thread_code(port), NULL);
if(thread1!=0) handle_error_en(thread1, "pthread_create");
thread2=pthread_create(&checkForNewDayThread, NULL, timer_thread_code(), NULL);
if(thread2!=0) handle_error_en(thread2, "pthread_create");
join=pthread_join(connectionHandlerThread, NULL);
if(join!=0) handle_error_en(join, "pthread_join");
return 0;
}
Note: I put only one pthread_join() because both threads should run forever, so to prevent returning from main it should suffice to join only one of the two.
Thanks in advance to anyone who helps me
When you call pthread_create like in your code :
thread1=pthread_create(&connectionHandlerThread, NULL, connection_thread_code(port), NULL);
You actually first call connection_thread_code(port) on the main thread, and pass the return value of that function call as parameter to pthread_create.
That's not what you want to do. You want to pass the function pointer as parameter to pthread_create, as well as the arguments to pass to it :
int port = 1234; /* <-- make sure this is in scope for the duration of the thread ! */
thread1 = pthread_create(&connectionHandlerThread, NULL, connection_thread_code, &port);
/* ... */
pthread_join(connectionHandlerThread, NULL);
For this to work, your thread function should have this signature :
void* connection_thread_code(void* port_ptr);
And get the port like so :
int port = *((int*) port_ptr);
Read up more on passing an int parameter to a thread function here.
Similarly for the second thread (pass the function pointer instead of calling the function, and change the signature).
I have a small problem and I don't find any solutions. I have this code.
Server code
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#define PORT 2908
extern int errno;
typedef struct thData{
int idThread;
int cl;
}thData;
static void *treat(void *);
void raspunde(void *);
int main ()
{
struct sockaddr_in server;
struct sockaddr_in from;
int nr;
int sd;
int pid;
pthread_t th[100];
int i=0;
if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
return errno;
}
int on=1;
setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
bzero (&server, sizeof (server));
bzero (&from, sizeof (from));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl (INADDR_ANY);
server.sin_port = htons (PORT);
/
if (bind (sd, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
{
return errno;
}
if (listen (sd, 2) == -1)
{
perror ("[server]Error at listen().\n");
return errno;
}
while (1)
{
int client;
thData * td;
int length = sizeof (from);
fflush (stdout);
if ( (client = accept (sd, (struct sockaddr *) &from, &length)) < 0)
{
perror ("[server]Error at accept().\n");
continue;
}
td=(struct thData*)malloc(sizeof(struct thData));
td->idThread=i++;
td->cl=client;
pthread_create(&th[i], NULL, &treat, td);
}//while
};
static void *treat(void * arg)
{
struct thData tdL;
tdL= *((struct thData*)arg);
printf ("[thread]- %d - Waiting the message...\n", tdL.idThread);
fflush (stdout);
pthread_detach(pthread_self());
raspunde((struct thData*)arg);
close ((intptr_t)arg);
return(NULL);
};
void raspunde(void *arg)
{
int nr, i=0;
struct thData tdL;
tdL= *((struct thData*)arg);
if (read (tdL.cl, &nr,sizeof(int)) <= 0)
{
printf("[Thread %d]\n",tdL.idThread);
perror ("Error at read() from client.\n");
}
printf ("[Thread %d]The message is...%d\n",tdL.idThread, nr);
nr++;
printf("[Thread %d]Sending the message back...%d\n",tdL.idThread, nr);
printf("%d\n",tdL.cl );
if (write (tdL.cl, &nr, sizeof(int)) <= 0)
{
printf("[Thread %d] ",tdL.idThread);
perror ("[Thread]Error at write() from client.\n");
}
else
printf ("[Thread %d]The message was sent.\n",tdL.idThread);
}
The above code is a server that creates for every client a thread. The client sends a number to the server and the server will answer back to the client with the number incremented by 1.
The question is how can I write for example the nr from the response function or a string message to all my clients that are connected on my server?
Thank you in advance!
As pointed out in the comments, you'll have to keep a list of active threads (protected by a mutex!) to know who is connected to your server.
When a thread is created it would be added to the list and when execution finishes it would remove itself. So you sould make the following changes:
Create a global list of threads and a pthread_mutex_t to protect it (this would happen in main)
Create a function to insert a thread to the list and a function to remove threads. Don't forget to take the mutex before modifying the list and release it after.
Add the insert in the treat function as the first instruction and the add the remove function before close (to prevent sending to a closed connection)
Define a broadcast function that takes a message, loops through the global list and sends the message to each client. Again don't forget to take the mutex while looping through the list and release it when done. You might also want to take into consideration skipping the sender of the broadcast.
The simplest way to implement this would be to use a singly linked list where you always insert at the head (to keep insertion fast) and remove items by their id. The function headers should look like this:
// your linked list
list_t* threadList;
pthread_mutex_t mutex;
void insert_list(thData* th);
// This could also return void, since to know the id you must already have the data that will be returned
thData* remove_list(int id);
// msg can have any type
void broadcast(int msg, int broadcasterId);
I've read answers to other similar questions, but none of them seemd to resolve my problem.
This is my code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
typedef struct {
pthread_t thread_id;
int sockfd;
} client_t;
client_t *clients;
size_t client_n = 0;
void *client_thread(void *client_ptr) {
client_t client = *(client_t*) client_ptr;
char buffer[500];
int state;
while(1) {
state = send(client.sockfd, 0, 1, MSG_NOSIGNAL);
if(state == -1) {
printf("socket-%d closed\n", client.sockfd);
break;
}
read(client.sockfd, buffer, 500);
printf("from socket-%d: %s\n", client.sockfd, buffer);
memset(buffer, 0, 500);
}
close(client.sockfd);
free(client_ptr);
client_n--;
}
int main(int argc, char *argv[]) {
int sockfd, newsockfd, clilen;
struct sockaddr_in clientaddr, serveraddr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(8080);
bind(sockfd, (struct sockaddr*) &serveraddr, sizeof(serveraddr));
listen(sockfd, 5);
clilen = sizeof(clientaddr);
clients = (client_t*) malloc(sizeof(client_t));
while(1) {
newsockfd = accept(sockfd, (struct sockaddr*) &clientaddr, &clilen);
printf("New connection: socket-%d\n", newsockfd);
clients = (client_t*) realloc(clients, (client_n + 1) * sizeof(client_t));
clients[client_n].sockfd = newsockfd;
pthread_create(&clients[client_n].thread_id, NULL, client_thread, (void*) &clients[client_n]);
client_n++;
}
return 0;
}
The program should listen for incoming connections and then create a new thread for each. The program will then handle each single client simultaneously. Since this should be the core of a game server, i created a structure to contain each players information.
It all worked fine untill i added the:
close(client.sockfd);
free(client_ptr);
client_n--;
Any idea what the problem is?
With
free(client_ptr);
client_n--;
there are two problems.
The first is the free call. You didn't actually call malloc (or realloc or calloc) for client_ptr. Instead client_ptr is pointing into an array that you allocated dynamically, but the element pointed to by client_ptr wasn't itself allocated dynamically separately. That leads to undefined behavior when you pass a pointer to free that wasn't actually allocated with malloc and family. Except for the very first element (i.e. clients[0]), when you instead free the whole array. The solution to this is to simply not call free in the thread.
The other problem is with the client_n-- expression. You don't protect this (or the corresponding client_n++ in the main function) from modification by other threads. That means two or more threads could possibly modify this simultaneously again leading to undefined behavior. You need to have a semaphore or mutex to protect this modification.
There are also a couple of other problems. For example you don't join the threads that have ended, leading to resource leaks. You don't check for errors or closed connection from the read call (a nicely closed connection is reported by the read call returning 0).
My terminal keep create and forking . I think i did something wrong in my code, i actually want fork when client connect, but when i launch the server, its sort of keep forking as i check with linux command "ps" ,how do i change my code to make it work properly.
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
using namespace std;
int main()
{
int serverFd;
int clientFd;
int serverLen;
int clientLen;
string message;
string serverSockAddrPtr;
struct sockaddr* serverSockAddressPnt;
struct sockaddr* clientSockAddressPnt;
struct sockaddr_un serverAddress;
struct sockaddr_un clientAddress;
// SOCKET CREATION PART - SERVER
serverFd = socket (AF_LOCAL, SOCK_STREAM, 0);
/* Set domain type */
serverAddress.sun_family = AF_LOCAL;
/* Set name */
strcpy (serverAddress.sun_path, "CountryServer");
/* GET SIZE OF Server Addres */
serverLen = sizeof serverAddress;
/* GET SIZE OF Client Addres */
clientLen = sizeof clientAddress;
/* Get Server Sock Address Pointer*/
serverSockAddressPnt = (struct sockaddr *) &serverAddress;
/* Get Client Sock Address Pointer*/
clientSockAddressPnt = (struct sockaddr *) &clientAddress;
/* Create file */
bind (serverFd, serverSockAddressPnt , serverLen);
/* listen for connection */
listen (serverFd,5);
// SOCKET CREATION END - SERVER
while(1)
{
//accept client connection
clientFd = accept(serverFd, clientSockAddressPnt, (socklen_t*)&clientLen);
if(fork()==0)
{
message="Successfully connected to the server";
write(clientFd,message.c_str(),strlen(message.c_str())+1);
close(clientFd);
exit(0);
}
else
close(clientFd);
}
return 0;
}
My question is:
How do i make the server to fork a process to handle client query when they connect.
I don't want it keep forking for no reasons.
Thanks for all help, this my first C coding to learn more about programming.
My client and server communicate through localhost, sockaddr_un and not internet.
What you should have for your loop is:
while (1) {
clientFd = accept(serverFd, clientSockAddressPnt, (socklen_t*)&clientlen);
if (clientFd >= 0) {
if(fork() == 0) {
message="Successfully connected to the server";
write(clientFd,message.c_str(),strlen(message.c_str())+1);
close(clientFd);
exit(0);
}
else
close(clientFd);
}
}
That way, you only ever fork when accept returns a nonnegative value (which means it completed successfully.
You should check the return value from accept(). You are getting an error, which you should fix.
The reason it keeps calling fork() is because every time you go around the loop, accept() returns (really quickly!) with an error instead of waiting for a new connection.
Hi I am trying to make a simple server that takes in an IP address from getaddrinfo() and binds to it. Using ifconfig, I've found that I have an ip address of wlan0 192.168.2.10 which I would like to bind to. Unfortunately the address I seem to be binding to is my lo device. For some reason when I initialize getaddrinfo("192.168.2.10","3490",&hings,&res); res gets returned to a NULL pointer. I will show off my code bellow.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <signal.h>
#define MAXDATASIZE 500;
int main(int argc, char *argv[]){
// dealing with client socket
struct sockaddr_storage their_addr;
socklen_t addr_size;
// server socket
struct addrinfo serverSide,*serverInfo,*sortIP;
int optValRet;
int listenSock, newSock;
// this is for reading in information
char buf[501];
char point[INET6_ADDRSTRLEN];
char compare[INET6_ADDRSTRLEN] = "192.168.2.10";
// this is for handeling child processes and signals
struct sigaction sa;
sa.sa_handler = NULL;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGCHLD, &sa, NULL) == -1){
printf("We have a problem, sigaction is not working.\n");
perror("\n");
exit(1);
}
// this sets up addrinfo
memset(&serverSide, 0, sizeof serverSide);
serverSide.ai_family = AF_UNSPEC;
serverSide.ai_socktype = SOCK_STREAM;
serverSide.ai_flags = INADDR_ANY;
// set up the address
if(getaddrinfo("192.168.2.10","3490",&serverSide,&serverInfo)!=0){
printf("get addr not success\n");
perror("\n");
return 1;
}
printf("Got address lists\n");
for(sortIP = serverInfo; sortIP = sortIP->ai_next; sortIP != NULL){
if((listenSock = socket(sortIP->ai_family, sortIP->ai_socktype, sortIP->ai_protocol))==-1){
continue;
}
if(setsockopt(listenSock,SOL_SOCKET,SO_REUSEADDR,&optValRet,sizeof(int))==-1){
perror("\n");
exit(1);
}
if(bind(listenSock,sortIP->ai_addr,sortIP->ai_addrlen) == -1 ){
perror("\n");
close(listenSock);
continue;
}
break;
}
if(sortIP == NULL){printf("sort ip is null.");}
inet_ntop(sortIP->ai_family,sortIP->ai_addr,point,sizeof point);
printf("Tell the clients connect to ip address %s on port 3490\n",point);
listen(listenSock, 10);
addr_size = sizeof their_addr;
newSock = accept(listenSock,(struct sockaddr *)&their_addr,&addr_size);
recv(newSock, buf, 500, 0);
printf("%s\n",buf);
close(listenSock);
close(newSock);
freeaddrinfo(serverInfo);
return 0;
}
Now I have some other questions beside the fact that I'm returning null. Since the wifi router has assigned me the ip address 192.168.2.10 for my subnet, how do I find out what my ip address is if I'm outside the network and trying to contact my server? I'm assuming the inside network ip is different from the outside network ip ... am I wrong? Anyways those are my two questions.
Thanks for any help!
This is wrong and is your immediate problem:
for (sortIP = serverInfo; sortIP = sortIP->ai_next; sortIP != NULL)
You want something like:
for (sortIP = serverInfo; sortIP != NULL; sortIP = sortIP->ai_next)
but I would go with a while loop personally.
To your main question, you should just bind to INADDR_ANY. That avoids that whole mess. Also:
recv(newSock, buf, 500, 0);
printf("%s\n",buf);
The %s format specifier is only for C-style strings, it's not for arbitrary binary data. Also, you throw away the return value from recv. There is no other way to know how many bytes you received.
As for finding your dynamic IP address from outside your network, use any of the dozens of IP posting services that assign you a host name and map it to your dynamic IP address.