I am writing a little server to learn about threading and also how to handle pointers with different structures and types but if I pass a sockaddr_in structure to the accept() function it fails. The program should respond to different input with the "correct/incorrect" data later to trick script kiddies and wasting their time. (I know things like inetsim already exsist but my main goal is learning with it.) But that's future music.
Inside while-loop in the main function the comment lines work (could be done better I think) but I need the sockaddr_in structure inside the threading function so I can create logfiles containing the connections ip address as its name. I created a structure with the client connection socket fd and an pointer to struct sockaddr_in so I can use it inside the threading function but like I said accept() failes with -1 all the time ending up in a segmentation fault (cause I don't catch it yet but I know I will have to later).
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <pthread.h>
#define LISTEN_BACKLOG 50
#define MAX_THREADS 100
void *handle_connection(void *args);
void *handle_connectionIP(void *args);
struct handle_connection_argument {
int conn;
struct sockaddr_in *peer;
};
int main(int argc, char *argv[])
{
pthread_t threads[MAX_THREADS];
int iret[MAX_THREADS];
int conn[MAX_THREADS];
for(int i=0; i < MAX_THREADS; i )
conn[i] = 0;
int sock;
char buf[1000];
struct sockaddr_in address_info;
struct handle_connection_argument connections[MAX_THREADS];
address_info.sin_family = AF_INET;
address_info.sin_port = htons(80);
address_info.sin_addr.s_addr = htonl(INADDR_ANY);
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1){
fprintf(stderr, "can not create socket\n");
exit(EXIT_FAILURE);
}
fprintf(stdout, "Created socket %d\n", sock);
if(bind(sock, (struct sockaddr*)&address_info, sizeof(address_info)) == -1){
fprintf(stderr, "can not bind to %s\n", address_info.sin_addr.s_addr);
exit(EXIT_FAILURE);
}
fprintf(stdout, "Bind to address %s\n", "0.0.0.0");
if(listen(sock, LISTEN_BACKLOG) == -1){
fprintf(stderr, "can not listen on %s\n", "0.0.0.0");
exit(EXIT_FAILURE);
}
fprintf(stdout, "Listening on %s\n", address_info.sin_addr.s_addr);
int counter = 0;
while(1){
//conn[counter] = accept(sock, (struct sockaddr*)NULL, NULL);
//iret[counter] = pthread_create(&threads[counter], NULL, handle_connection, (void *)&conn[counter]);
connections[counter].conn = accept(sock, (struct sockaddr*)&connections[counter].peer, NULL);
iret[counter] = pthread_create(&threads[counter], NULL, handle_connectionIP, (void *)&connections[counter]);
counter ;
}
for(int i=0; i < MAX_THREADS; i ) //useless because I don't leave the while loop yet?
pthread_join(threads[counter], NULL);
sleep(1);
}
void *handle_connectionIP(void *args)
{
//printf("inside thread function\n");
int n; // bytes received
char *ip; // pointer for holding ip address from connected client
int *conn; // socket for client connection
struct sockaddr_in *peer; // sockaddr_in with peer data
struct handle_connection_argument *connection; // argument give to handle_connectionIP function
connection = (struct handle_connection_argument *)args;
conn = &connection->conn;
printf("%d\n", *conn);
peer = (struct sockaddr_in*) connection->peer;
ip = inet_ntoa(peer->sin_addr);
char buf[1000];
char filename[20];
sprintf(filename, "connection%d.log", *conn);
FILE *file;
file = fopen(filename, "w");
//peer_address = inet_ntoa(connection->peer->sin_addr);
printf("Connection %d from %s is managed by Thread (ID:%ld)\n", *conn, ip, pthread_self());
while((n = recv(*conn, buf, strlen(buf)-1, 0)) > 0) {
printf("%s", buf);
fprintf(file, "%s", buf);
}
printf("Connection %d closed.\n", *conn);
fclose(file);
}
void *handle_connection(void *args)
{
//printf("inside thread function\n");
int n;
int *conn;
conn = (int *)args;
char buf[1000];
char filename[20];
sprintf(filename, "connection%d.log", *conn);
FILE *file;
file = fopen(filename, "w");
//peer_address = inet_ntoa(connection->peer->sin_addr);
printf("Connection %d is managed by Thread (ID:%ld)\n", *conn, pthread_self());
while((n = recv(*conn, buf, strlen(buf)-1, 0)) > 0) {
printf("%s", buf);
fprintf(file, "%s", buf);
}
printf("Connection %d closed.\n", *conn);
fclose(file);
pthread_exit((void *)pthread_self());
}
I tried everything with changing how I access the structure but I still don't get it. I would appreciate any improvements and explaination what I am doing wrong here. Also improvements to the code itself (I don't mean style but maybe best practice or whats not well implemented or handled)
That is my first program with threading and networking. I just wrote simple stuff with handling files before so please don't be too hard :P
CodePudding user response:
I would post this as a comment but I don't have enough rep. I'm pretty sure with accept()
, the second argument should be the network structure you defined earlier (in this case it would be address_info
). eg: accept(sock, (stuct sockaddr*)&address_info, NULL);
Hopefully this is the answer you're looking for!
CodePudding user response:
You're not passing an argument that is the correct type:
connections[counter].conn = accept(sock,(struct sockaddr*)&connections[counter].peer,NULL);
connections[counter].peer
has type struct sockaddr_in *
, so the address of that variable has type struct sockaddr_in **
which is not what the function is expecting.
You could pass the peer
member directly, but that's still a problem because you have a pointer that isn't pointing anywhere.
Change the struct definition so peer
isn't a pointer:
struct handle_connection_argument {
int conn;
struct sockaddr_in peer;
};
And make an associated change in your thread function:
peer = &connection->peer;