0

I'm creating a TCP socket-based server-client application for a roulette game. Before compiling the server, the admin needs to input two arguments for how the server should work: one for the port, and the other for the roulette's required time to spin. However, when I try to compile the code it gives me a segmentation fault error. The code works fine if all references to roulette_time are taken out, though.

#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <semaphore.h>

#define BACKLOG 15

long bank = 0;

typedef struct pthread_arg_t{
  int new_socket_fd;
  struct sockaddr_in client_address;
  int port;
  int *roulette_time;
  /*Inserire le variabili passate dal client qui*/
  int picked_num;
  long stake;
  int won;
}pthread_arg_t;

void *pthread_routine(void *arg);
void signal_handler(int signal_number);

int main(int argc, char *argv[]){
  int port, socket_fd, new_socket_fd, chosen_number, won, roulette_time;
  long stake;
  struct sockaddr_in address;
  pthread_attr_t pthread_attr;
  pthread_arg_t *pthread_arg;
  pthread_t pthread;
  socklen_t client_address_len;

  port = atoi(argv[1]);
  roulette_time = atoi(argv[2]);
  if(port == NULL){
    printf("Inserisci il port qui\n");
    scanf("%d",&port);
  }

  if(roulette_time == NULL){
    printf("Inserisci il tempo minimo da far trascorrere prima dell'azionamento della roulette\n");
    scanf("%d",&roulette_time);
    }
  pthread_arg->roulette_time = &roulette_time;

  memset(&address,0,sizeof(address));
  address.sin_family = AF_INET;
  address.sin_port = htons(port);
  address.sin_addr.s_addr = INADDR_ANY;

  if((socket_fd = socket(AF_INET,SOCK_STREAM,0)) == -1){
    perror("creazione socket");
    exit(1);
  }

  if(bind(socket_fd,(struct sockaddr*)&address, sizeof(address)) == -1){
    perror("binding");
    exit(1);
  }

  if(listen(socket_fd, BACKLOG) == -1){
    perror("listen");
    exit(1);
  }
  
  if((signal(SIGPIPE, SIG_IGN) == SIG_ERR) || (signal(SIGTERM, signal_handler) == SIG_ERR) || (signal(SIGINT, signal_handler) == SIG_ERR)){
    perror("signal");
    exit(1);
  }

  if(pthread_attr_init(&pthread_attr) != 0){
    perror("pthread_attr_init");
    exit(1);
  }

  if(pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED) != 0){
    perror("pthread_attr_setdetachstate");
    exit(1);
  }

  while(1){
    pthread_arg = (pthread_arg_t *)malloc(sizeof *pthread_arg);
    if(!pthread_arg){
      perror("malloc");
      continue;
    }

    client_address_len = sizeof(pthread_arg->client_address);
    new_socket_fd = accept(socket_fd, (struct sockaddr *)&pthread_arg->client_address,&client_address_len);
    if(new_socket_fd == -1){
      perror("accept");
      free(pthread_arg);
      continue;
    }

    pthread_arg->new_socket_fd = new_socket_fd;
    /*Inizializza tutte le variabili qui*/
    chosen_number = pthread_arg->picked_num;
    stake = pthread_arg->stake;
    won = pthread_arg->won;

    if(pthread_create(&pthread, &pthread_attr, pthread_routine, (void*)pthread_arg) != 0){
      perror("pthread_create");
      free(pthread_arg);
      continue;
    }
  }
  return 0;
}

void *pthread_routine(void *arg){
  pthread_arg_t *pthread_arg = (pthread_arg_t *)arg;
  int new_socket_fd = pthread_arg->new_socket_fd;
  struct sockaddr_in client_address = pthread_arg->client_address;
  int roulette_num, picked_num, won, accept_time = pthread_arg->roulette_time;
  long stake;
  time_t start, end;
  sem_t mutex;
  free(arg);
  /*Inserisci codice roulette qui*/
  while(1){
    if(start == NULL){
      start = time(NULL);
      end = start + accept_time;
    }
    read(new_socket_fd, &picked_num, sizeof(picked_num));
    read(new_socket_fd, &stake, sizeof(stake));
    printf("Puntata ricevuta: numero %d, %d crediti\n",ntohl(picked_num), ntohl(stake));
    bank = bank + stake;
    printf("Soldi del banco: %d crediti\n",ntohl(bank));
    start = time(NULL);
    if(start >= end){
      roulette_num = (rand() % (36 - 0 + 1)) + 0;
      printf("Numero estrtatto dalla roulette: %d\n",roulette_num);
      int converted_roulette_num = htonl(roulette_num);
      write(new_socket_fd,&converted_roulette_num,sizeof(int));
      if(read(new_socket_fd,&won,sizeof(int)) == 1){
    int converted_bank = htonl(bank);
    write(new_socket_fd,&converted_bank,sizeof(converted_bank));
    bank = 0;
      }
      start = NULL;
    }
  }
  close(new_socket_fd);
  return NULL;
}

void signal_handler(int signal_number){
}

Edit: The input that this application accepts is ./server [socket port number] [seconds to activate roulette], for example: ./server 24106 30 (in this case 24106 is the socket port number, and we're asking the roulette to spin after 30 seconds have passed). The output should appear in the following way: after the server receives an input from a connected client, the server prints the received number and the stake. After the amount of time passed as argument passed, the roulette spins and the server prints out the extracted number. However, as mentioned earlier, this only happens if I remove every instance of roulette_time from the code - otherwise I get Segmentation fault (core dumped) every time I try to run it.

  • Why are you comparing integers with `NULL`? And what does your question title have to do with anything? In any case, if you have a segmentation fault, you need to use a **debugger** and figure out **where** (at what line) and **why** (because of what variable) you have a segmentation fault. Asking people to look at your code and figure it out for you is unlikely to work. – n. m. could be an AI Feb 03 '21 at 17:13
  • 1
    `read(new_socket_fd,&won,sizeof(int)) == 1`? You need to look at `read()` a bit more closely, especially what the return value is. – Andrew Henle Feb 03 '21 at 17:14
  • Please [edit] your question and show the input you use and the output you get. Run your program in a debugger to see at which point you get a segmentation fault: Hint: You must check `argc` to find out if `argv[1]` or `argv[2]` is valid before passing them to `atoi()`. – Bodo Feb 03 '21 at 17:14
  • 1
    You are creating **detached** threads (why? what are the advantages over normal threads in your application?) and you are passing them a pointer to a variable local to `main`. This isn't going to end well because your threads outlive `main`. – n. m. could be an AI Feb 03 '21 at 17:18
  • However first of all please look at [this](https://godbolt.org/z/335a76), then read [this](https://stackoverflow.com/questions/57842756/). – n. m. could be an AI Feb 03 '21 at 17:20
  • @n.'pronouns'm. ?? the address passed is malloced. The OP probably detaches tbe threads so it does not have to deal with all that join rubbish when the client disconnects. – Martin James Feb 03 '21 at 18:33
  • This: 'free(pthread_arg);' after the pthread_create is a bigger issue - you should free the arg in the thread function, just before it exits. Why free it in main() - it would very likely be gone before the thread function gets it:( – Martin James Feb 03 '21 at 18:35
  • @MartinJames `pthread_arg->roulette_time = &roulette_time;` – n. m. could be an AI Feb 03 '21 at 20:28
  • @n.'pronouns'm. ....ahh. – Martin James Feb 03 '21 at 22:07
  • ..OTOH, main() runs the 'while 1' accept loop and so does not return, so stack vars are not deallocated. 'roulette_time' is not modified during the run, so the threads should be able to read it safely. – Martin James Feb 03 '21 at 22:12
  • 1
    ..OTOOH, when 'pthread_arg->roulette_time = &roulette_time;', 'pthread_arg' is not mallocated. That load needs to be moved until after the malloc. – Martin James Feb 03 '21 at 22:16
  • Hmmm... whole lotta segfault-bait you have there:) – Martin James Feb 03 '21 at 22:18
  • @MartinJames I added a malloc on the first statement of pthread_arg_t and now it's running as it should be. Turns out the code was missing just that. Big thanks. – Nicholas Marsicano Feb 04 '21 at 10:36

0 Answers0