Newsgroup: it.comp.os.linux.development
Titolo: Perché non va questa accept?

Mi sono bloccato nello sviluppo di un programma per l'università e non so
come andarne fuori. Deve essere una monata, però non trovo l'errore... Mi
ritorna EINVAL, ma non so perchè... 
L'errore viene fuori in wait_for_monitor, dove l'accept fallisce e non
capisco perché.
Lo compilo sotto linux col gcc. Scusate se il post è lungo...
Grazie
#include <pthread.h>    /* per i thread, ricordarsi il flag -lpthread */
#include <sys/types.h>  /* socket(), bind(), accept()                 */
#include <sys/socket.h> /* socket(), bind(), listen(), accept()       */
#include <netinet/in.h> /* struct sockaddr_in                         */
#include <stdio.h>      /* FILE* e tutte le printf()                  */
#include <semaphore.h>  /* per avere i semafori                       */
#include <unistd.h>     /* write()                                    */
#include <stdlib.h>     /* malloc(), free()                           */
#include <errno.h>      /* errno                                      */
extern int errno;
#define CLIENTPORT      2688
#define MONITORPORT     2689
#define BUFSIZE         1024
/*
 * Schema dei thread:
 *
 * +------------+        +--------------+
 * | principale |---+--->| queueCleaner |
 * +------------+   |    +--------------+
 *                  |
 *                  |    +---------+        +-------------+
 *                  +--->| monitor |---+--->| fromMonitor |
 *                  |    +---------+   |    +-------------+
 *                  |                  |
 *                  |                  |    +-----------+
 *                  |                  +--->| toMonitor |
 *                  |                       +-----------+
 *                  |
 *                  |    +----------------------------+
 *                  +--->| i thread della thread_list |
 *                       +----------------------------+
 */ 
/**
 * Nodo della lista dei thread.
 */
typedef struct _thread_list_t 
{
  /** Il thread associato al nodo. */
  pthread_t thread;
  /** Il socket gestito dal thread. */
  int socket;
  /** Puntatore al prossimo nodo della lista. */
  struct _thread_list_t *next;
} thread_list_t;
/**
 * Nodo della lista  dei messaggi. I messaggi vengono  accodati dai vari
 * thread che gestiscono i socket e poi vengono rimossi uno dopo l'altro
 * dalla testa dal thread che si occupa del loro inoltro.
 */
typedef struct _message_queue_t
{
  /** Buffer per i messaggi. */
  char message[BUFSIZE];
  /** Prossimo nodo della lista. */
  struct _message_queue_t *next;
} message_queue_t;
/* Puntatore globale alla testa della coda dei thread. */
thread_list_t *thread_list;
/* Puntatore globale alla testa della coda dei messaggi per i client. */
message_queue_t *message_queue;
/* Puntatore globale alla testa della  coda dei messaggi per il monitor.
 */
message_queue_t *monitor_queue;
/* Semaforo che controlla l'accesso alla lista dei thread. */
sem_t *thread_list_semaphore;
/* Semaforo che controlla l'accesso alla lista dei messaggi. */
sem_t *message_queue_semaphore;
/**
 * Funzione di gestione delle connessioni. Ogni volta che viene eseguito
 * un nuovo thread questo esegue questa funzione. Il suo scopo e' quello
 * di ricevere  le varie richieste dai  client e di metterle  nella coda
 * dei messaggi.
 *
 * @param  thread_list_item Il  puntatore all'elemento  della lista  dei
 * tread. Ci serve per sapere  il filedescriptor del socket associato al
 * thread. Non  si puo' passare  direttamente il valore  di slaveSocket,
 * perche' potrebbero esserci problemi di  concorrenza. NON va usato per
 * nessun'altro motivo, perche' altrimenti  si rischia di distruggere la
 * coda dei thread.
 */
void handle_connection (void* thread_list_item) ;
/**
 * Handler del  thread che si occupa  di svuotare la coda  dei messaggi.
 * Semplicemente rimuove il messaggio in testa alla coda e lo replica su
 * tutti i socket e quindi lo invia quindi a tutti i thread.
 */
void manage_message_queue (void) ;
/**
 * Gestisce i comandi che arrivano dal monitor e li copia nella coda dei
 * messaggi destinati ai client.
 *
 * @param   socketDescriptor   Il   descrittore   del   socket.   Questa
 * volta,  a  differenza della  funzione  <code>handle_connection</code>
 * posso  passare   il  descrittore   del  socket  perché   la  funzione
 * <code>wait_for_monitor</code>    non    cicla   di    continuo,    ma
 * per   avviare   una   nuova   iterazione   aspetta   la   morte   dei
 * thread   associati   a   <code>manage_message_from_monitor</code>   e
 * <code>manage_message_to_monitor</code> .  A quel  punto, anche  se il
 * descrittore del socket cambia non interessa più.
 */
void manage_message_from_monitor (void* socketDescriptor) ;
/**
 * Invia   i  comandi   di   aggiornamento  al   monitor  (per   esempio
 * l'aggiornamento  del  canvas  se   simulamo  ambienti  wireless).  La
 * funzione  <code>manage_message_queue</code> si  occupa di  spostare i
 * messaggi dalla coda  dei messaggi che arrivano dai  client nella coda
 * dei messaggi verso il server.
 *
 * @param   socketDescriptor   Il   descrittore   del   socket.   Questa
 * volta,  a  differenza della  funzione  <code>handle_connection</code>
 * posso  passare   il  descrittore   del  socket  perché   la  funzione
 * <code>wait_for_monitor</code>    non    cicla   di    continuo,    ma
 * per   avviare   una   nuova   iterazione   aspetta   la   morte   dei
 * thread   associati   a   <code>manage_message_from_monitor</code>   e
 * <code>manage_message_to_monitor</code> .  A quel  punto, anche  se il
 * descrittore del socket cambia non interessa più.
 */
void manage_message_to_monitor (void* socketDescriptor) ;
/**
 * Aspetta la connessione del monitor e provvede ad avviare i due thread
 * per lo scambio dei messaggi.
 */
void wait_for_monitor (void) ;
/**
 * Funzione  di  avvio.  Effettuta le  inizializzazioni  necessarie  per
 * accettare connessioni e  si mette in attesa  di ricevere connessioni.
 * Per ogni  nuova connessione viene  creato un  thread (e non  un task,
 * cosi' riduciamo le risorse di sistema impiegate).
 *
 * Cosa rimane da fare:
 * 1) il thread che accetta comandi dal monitor.
 * 2) accettare parametri da riga di comando.
 */
int main (void) {
        int serverSocket;         /* socket in ascolto                  */
        int slaveSocket;          /* socket per gestire le connessioni  */
        int raddrlen;             /* lunghezza della struttura raddr    */
        struct sockaddr_in laddr; /* il nostro indirizzo locale         */
        struct sockaddr_in raddr; /* indirizzo remoto di chi si collega */
        pthread_t queueCleaner;   /* thread che svuota la message_queue */
        pthread_t monitor;        /* aspetta la connessione del monitor */
        /* inizializziamo le due strutture dati. */
        thread_list = NULL;
        message_queue = NULL;
        monitor_queue = NULL;
        /* inizializzazione dei semafori */
        thread_list_semaphore = (sem_t*) malloc (sizeof (sem_t));
        message_queue_semaphore = (sem_t*) malloc (sizeof (sem_t));
        sem_init (thread_list_semaphore, 0, 1);
        sem_init (message_queue_semaphore, 0, 1);
        /* avviamo i thread di servizio */
        pthread_create (&queueCleaner, NULL,
                        (void*) &manage_message_queue, NULL );
        pthread_create (&monitor, NULL,
                        (void*) &wait_for_monitor, NULL );
        /* creiamo un socket */
        serverSocket = socket (PF_INET, SOCK_STREAM, 0);
        if (serverSocket == -1) {
                fprintf (stderr, "errore nella creazione del socket\n");
                exit(1);
        }
        /* mettiamo in laddr il nostro indirizzo di binding */
        memset (&laddr, 0, sizeof(laddr));
        laddr.sin_family = AF_INET;
        laddr.sin_port = htons(CLIENTPORT);
        laddr.sin_addr.s_addr = htonl (INADDR_ANY);
        /* colleghiamo il socket all'indirizzo di binding */
        if (bind (serverSocket, (struct sockaddr*) &laddr, sizeof(laddr))==-1) {
                fprintf (stderr, "errore nel binding del socket\n");
                exit (1);
        }
        /* mettiamoci in ascolto */
        if (listen (serverSocket, 5) == -1) {
                fprintf (stderr, "errore nel listen\n");
                exit (1);
        }
        /* creiamo un ciclo infinito in attesa di connessioni */
        while (1) {
                thread_list_t *new;
                thread_list_t *pointer;
                /* accettiamo le connessioni */
                raddrlen = sizeof (raddr);
                slaveSocket = accept (serverSocket, (struct sockaddr *) &raddr,
                                      &raddrlen);
                if (slaveSocket == -1) {
                        fprintf (stderr, "errore nell'accept del client\n");
                        exit (1);
                } else {
                        new = (thread_list_t*) malloc (sizeof (thread_list_t));
                        /* compiliamo il nuovo nodo della lista */
                        new->socket = slaveSocket;
                        pthread_create (&(new->thread), NULL,
                                        (void*) &handle_connection,(void*) new);
                        /* aggiungiamo il nuovo thread alla lista dei thread */
                        sem_wait (thread_list_semaphore);
                        if (thread_list == NULL) {
                                thread_list = new;
                                new->next = NULL;
                        } else {
                                pointer = thread_list;
                                while (pointer->next != NULL)
                                        pointer = pointer->next;
                                pointer->next = new;
                                new->next = NULL;
                        }
                        sem_post (thread_list_semaphore);
                }
        }
        exit(0);
}
void handle_connection (void* thread_list_item) {
        FILE *stream;
        char *c;
        thread_list_t *item = (thread_list_t*) thread_list_item;
        /* associamo lo stream al socketdescriptor */
        stream = fdopen(item->socket, "r");
        setbuf (stream, NULL);
        /* mettiamoci in attesa di richieste dal client */
        while (1) {
                message_queue_t *new;
                message_queue_t *pointer;
                new = (message_queue_t*) malloc (sizeof (message_queue_t));
                c = fgets (new->message, BUFSIZE, stream);
                /* controlliamo se il client ha chiuso il socket */
                if (c== NULL) {
                        fprintf (stderr, "socket chiuso\n");
                        pthread_exit (0);
                }
                pointer = message_queue;
                sem_wait (message_queue_semaphore);
                if (pointer == NULL) {
                        message_queue = new;
                        new->next = NULL;
                } else {
                        while (pointer->next != NULL)
                                pointer = pointer->next;
                        pointer->next = new;
                        new->next = NULL;
                }
                sem_post (message_queue_semaphore);
        }
}
void manage_message_queue (void) {
#warning "FIXME: implementare il passaggio dei messaggi dalla coda dei messaggi a quella del monitor"
        message_queue_t *messagePointer;
        thread_list_t *threadPointer;
        while (1) {
                /* estraiamo il primo messaggio dalla coda */
                sem_wait (message_queue_semaphore);
                messagePointer = message_queue;
                if (message_queue != NULL) {
                        message_queue = message_queue->next;
                }
                sem_post (message_queue_semaphore);
                if (messagePointer == NULL) goto end;
                /* replichiamo il messaggio su tutte le connessioni */
                sem_wait (thread_list_semaphore);
                threadPointer = thread_list;
                while (threadPointer != NULL) {
                        FILE *stream = fdopen(threadPointer->socket, "w");
                        setbuf (stream, NULL);
                        fprintf (stream, messagePointer->message);
                        fclose (stream);
                        threadPointer = threadPointer->next;
                }
                sem_post (thread_list_semaphore);
                free (messagePointer);
                end:
        }
}
void wait_for_monitor (void) {
        int mserverSocket;        /* socket in ascolto                  */
        int mslaveSocket;         /* socket per gestire le connessioni  */
        int mraddrlen;            /* lunghezza della struttura raddr    */
        struct sockaddr_in mladdr;/* il nostro indirizzo locale         */
        struct sockaddr_in mraddr;/* indirizzo remoto di chi si collega */
        pthread_t fromMonitor;    /* thread che riceve dal monitor      */
        pthread_t toMonitor;      /* thread che invia al monitor        */
        /* creiamo un socket */
        mserverSocket = socket (PF_INET, SOCK_STREAM, 0);
        if (mserverSocket == -1) {
                fprintf (stderr, "errore nella creazione del socket\n");
                exit(1);
        }
        /* mettiamo in laddr il nostro indirizzo di binding */
        memset (&mladdr, 0, sizeof(mladdr));
        mladdr.sin_family = AF_INET;
        mladdr.sin_port = htons(MONITORPORT);
        mladdr.sin_addr.s_addr = htonl (INADDR_ANY);
        /* colleghiamo il socket all'indirizzo di binding */
        if (bind (mserverSocket, (struct sockaddr*) &mladdr, sizeof(mladdr))==-1) {
                fprintf (stderr, "errore nel binding del socket\n");
                exit (1);
        }
        /* creiamo un ciclo infinito in attesa di connessioni */
        while (1) {
                /* accettiamo le connessioni */
                mraddrlen = sizeof (mraddr);
                mslaveSocket = accept (mserverSocket, (struct sockaddr *) &mraddr,
                                      &mraddrlen);
                if (mslaveSocket == -1) {
                        fprintf (stderr, "errore nell'accept del monitor\n");
                        if (errno == EINVAL)
                                fprintf (stderr, "codice d'errore: EINVAL\n");
                        exit (1);
                } else {
                        pthread_create (&fromMonitor, NULL,
                                        (void*) &manage_message_from_monitor,
                                        (void*) mslaveSocket);
                        pthread_create (&toMonitor, NULL,
                                        (void*) &manage_message_to_monitor,
                                        (void*) mslaveSocket);
                }
                /* prima di reiterare aspettiamo che i thread muoiano. */
                pthread_join (fromMonitor, NULL);
                pthread_join (toMonitor, NULL);
        }
}
void manage_message_from_monitor (void* socketDescriptor) {
}
void manage_message_to_monitor (void* socketDescriptor) {
}

 l'errore... Mi ritorna EINVAL, ma non so perchè...
ecco, sono un coglione. manca la listen, porco giuda... per fortuna che
su 
irc.debian.org
 c'è molta gente disponibile.