/* Programma:    servente_c
*  Autore:       FF
*  Data:         05/02/2006
*  Descr.:       Esempio di servente concorrente TCP che accetta connessione,
*                la registra su un file di log  e riceve un file dal cliente da 
*                memorizzare nella directory corrente con nome composto
*                da ip_cliente:porta_data_ora;
*/
#include "utilsock.h"
/* utilsock.h contiene tutte le inclusioni delle altre librerie necessarie
*  e le funzioni di lettura e scrittura dal socket
*/
#define MAX        80
#define BACKLOG 20

int main(int argc, char *argv[])
{
    int sd, accsd,fd,fdw,l,scritti,letti;
    struct sockaddr_in serv_ind, cliente;
    char buffer[MAX],datil[MAX],indcli[128];
    socklen_t lung;
    pid_t pid;
    in_port_t porta;
    char stringa[MAX], stringa2[MAX];
    time_t    now;
    struct    tm    *tnow;        // struttura definita in &lt;time.h&gt;
    char tempo[24], tempo2[24];
    if (argc != 2) {
        printf("\nErrore\n");
        printf("Attivare con ./servente_c porta(>1023)\n");
        exit(-1);
    }
    // apertura file di log con xor fra i flag O_RDWR, O_CREAT, O_APPEND
    // definiti in &lt;fcntl.h&gt;; apre in lettura-scrittura, append e lo
    // crea se serve     
    fd=open("log_servente", O_RDWR |O_CREAT | O_APPEND,0644);
    // crea socket 
    if ( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Errore nella creazione del Socket");
        exit(-1);
    }
    // indirizzo ip
    memset((void *)&serv_ind, 0, sizeof(serv_ind)); // pulizia ind
    serv_ind.sin_family = AF_INET;                  // ind di tipo INET 
    porta = atoi(argv[1]);
    serv_ind.sin_port = htons(porta);               // porta 
    serv_ind.sin_addr.s_addr = htonl(INADDR_ANY);   // connessioni da ogni ip
    // bind 
    if (bind(sd, (struct sockaddr *)&serv_ind, sizeof(serv_ind)) < 0) {
        perror("Errore nella bind");
        exit(-1);
    }
    // listen 
    if (listen(sd, BACKLOG) < 0 ) {
        perror("Errore nella listen");
        exit(-1);
    }
    printf ("Servente in ascolto sulla porta %d\n",porta); 
    printf ("'Ctrl+c' per chiuderlo\n\n");
    lung = sizeof(struct sockaddr_in); //lung della giusta dimensione
    // accetta connessione
    while (1) {
        if ((accsd = accept(sd, (struct sockaddr *)&cliente, &lung))<0) {
            perror("Errore nella accept");
            exit(-1);
        }
        if ((pid=fork()) <0) {
            perror("Errore nella fork");
            exit(-1);        
        }
        if (pid == 0) {      // figlio
            close(sd);
            time (&now);
            tnow = localtime(&now);
            strftime(tempo,24,"%b %d %H:%M:%S %Y",tnow);
            strftime(tempo2,24,"%Y_%b_%d_%H:%M:%S",tnow);
            inet_ntop(AF_INET, &cliente.sin_addr, indcli, sizeof(indcli));
            l=strlen(indcli);
            snprintf(stringa,55+l,"%s Richiesta da nodo %s, porta %5d\n",
                     tempo,indcli,ntohs(cliente.sin_port));
            snprintf(stringa2,30+l,"%s:%5d_%s",indcli,ntohs(cliente.sin_port),
                     tempo2);
            printf("%s",stringa);        
            write (fd,stringa,strlen(stringa));        // scrive nel file di log        
            strcpy(buffer,"Connessione accettata\n");
            if ( (scrivisock(accsd, buffer, strlen(buffer))) < 0 ) {
                perror("Errore nella write");
                exit(-1);
            }
            // apertura file di output con xor fra i flag O_RDWR, O_CREAT
            // lettura-scrittura e lo crea se serve     
            fdw=open(stringa2, O_RDWR |O_CREAT | O_APPEND,0644);
            // scrive nel file di output i dati letti dal socket
            // per leggere usa leggisock() definita in utilsock.h
            while(1) {
                if((letti=leggisock(accsd,datil,MAX))==0) 
                    break;            
                scritti=write(fdw,datil,letti);
            }    
            close(accsd);
            exit(0);
        }
        else  {              // padre         
            close(accsd);
        }        
    }
close(fd);
close(fdw);    
exit(0);
}

