Problema di trasferimento sul canale dati con server c FTP

di il
1 risposte

Problema di trasferimento sul canale dati con server c FTP

Salve, sto' applicando il pezzo di codice trovato qui http://www.tenouk.com/ModuleA1.htm c per poter inviare dal server al client
il risultato del comando dir del client.
Debugando lato server vedo che tutto il contenuto del risultato
del comando dir viene inviato pure il nome di eventuali file messi
da me dentro la cartella da listare.
Tant'e' vero che alla fine del comando mi viene inviato il numero dei caratteri inviati pero' mi da' 0 caratteri ricevuti e questo non me lo spiego
dato che la funzione lato client che si occupa del conteggio dei caratteri ricevuti e di stamparli funge bene.
Debugando lato client vedo invecie che a volte lo stampaggio a monitor
del risultato del comando dir si pianta sempre a questo punto "\nRDO SYS H e poi si pianta dentro la funzione ricevi() e non me ne spiego il motivo, debugando invecie nel lato server invecie riesce a stampare tutto il contenuto senza problemi tranne per il fatto che non so' perche' ma il server invia il nome degli eventuali file interni ma il client non ne stampa il nome ma stampa solo i file "." e "..".
Non riesco quindi a capire il motivo per cui debugando nel lato client
succede che a volte la stampa si ferma nel punto di cui ho spiegato
prima o piu' avanti in base a come gli gira e questo non ha senso logico
dato che se c'e' un problema o ti pianti sempre in un punto o sempre
in un altro.
Questo e' la parte di codice del client in cui si pianta
    else
    {
    //ricevi il risultato del comando LIST dal canale dati
    //e stampalo a monitor
    if(caratteri_rx=ricevi_dati(PRINT)==-1)
    {
    closep(conn_sock_dati); //chiudi il canale dati se hai riscontrato un problema di ricezione
    }
    else
    {
    //ricevi il numero di caratteri spediti e stampali
    ricevi(recvchar); //SI PIANTA SEMPRE DENTRO A QUESTA
    caratteri_tx=atoi(recvchar);
    printf("Numero di caratteri trasmessi: %d\n", caratteri_tx);
    printf("Numero di caratteri ricevuti: %d\n", caratteri_rx);
    }
Posto di seguito i due sorgenti:

client:
//client FTP

    #define WIN32_LEAN_AND_MEAN
    #include <winsock2.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>


    //porta default
    #define DEFAULT_PORT 20
    //lunghezza dei buffer di ricezione e trasmissione
    #define DEFAULT_BUFFER 2048
    #define BUFFER 1024
    //indirizzo di default
    #define ADDRESS "127.0.0.1"
    //dechiarazione macro di abilitazione
    #define SEND_ON 1
    #define SEND_OFF 2
    //dichiarazione macro dei comandi
    #define USER 3
    #define RUSER 4
    #define COM 5
    #define PASS 6
    #define LIST 7
    #define RECV 9
    #define CDUP 10
    #define CWD  11
    #define DELE 12
    #define MKD  13
    #define QUIT 14
    #define HELP 15
    #define RETD 16
    #define STOR 17
    #define PORT 18
    #define PATH 19
    #define RMD  20
    //macro per indicare la stampa o meno del file
    #define PRINT 21

    //#define LINUX  //decommentare questa macro per compilare sotto linux

    char sendchar[BUFFER];
    char recvchar[DEFAULT_BUFFER];
    int n_char;
    //definisci indirizzo
    char *address=ADDRESS;
    //definisci porta
    u_short porta_comandi=DEFAULT_PORT;
    //variabile di abilitazione di invio/ricezione sul canale dati
    int en_send;
    int comando;
    int retval;
    int i;
    unsigned int addr;
    struct sockaddr_in server_com, server_dati;
    struct hostent *hp;
    WSADATA wsaData;
    SOCKET  conn_sock_com, conn_sock_dati;


    int ricevi(char *buffer);
    int ricevi_dati(int com);
    int invia(char *buffer, int len);
    SOCKET creasocket(int dominio, int tipo_socket, int protocollo);
    int connectp(SOCKET sock, struct sockaddr_in *ind, char *addr, short dominio, u_short porta);
    int recvp(SOCKET s, char *buf, int len, int flags);
    int sendp(SOCKET s, const char *buf, int len, int flags);
    int errorp(void);
    void inserisci_user(void);
    void inserisci_comando(void);
    void inserisci_pass(void);
    int com_server(void);
    int comandi(void);
    u_short conv_chartoshort(char *recvchar);
    void inter_comandi(int com);
    void componi_comando(int com);
    void sostituisci(char *FTP_com, int len);

    int main(int argc, char **argv)
    {
        int x;
        int caratteri_rx;
        int caratteri_tx;
        u_short porta_dati;
        if ((retval=WSAStartup(0x202, &wsaData)) != 0)
        {
            fprintf(stderr,"WSAStartup() fallita con errore %d\n", retval);
            WSACleanup();
            return -1;
        }


        /*if(hp==NULL )
        {
            fprintf(stderr,"impossibile risolvere l'indirizzo \"%s\": Error %d\n", server_name, WSAGetLastError());
            WSACleanup();
            exit(1);
        }*/
        //crea socket
        conn_sock_com=creasocket(AF_INET, SOCK_STREAM, 0);
        if(conn_sock_com<0 )
        {
            fprintf(stderr,"Errore di apertura della socket: Error %d\n", WSAGetLastError());
            WSACleanup();
            return -1;
        }
        //printf("il client si sta connettendo a: %s.\n", hp->h_name);
        if(connectp(conn_sock_com ,(struct sockaddr*)&server_com, ADDRESS, AF_INET, porta_comandi)==-1)
        {
            fprintf(stderr,"connessione fallita: %d\n", errorp());
            WSACleanup();
            return -1;
        }
        while(1)
        {
            //ricevi la risposta dal server e mettila in recvchar
            if(ricevi(recvchar)==-1)     break;   //se il ritorno e' -1 chiudi la socket
            //stampa il buffer sul monitor solo nei casi in cui non ricevi il comando PORT
            //o il comando PATH
            if(com_server()==0)     printf("\n%s",recvchar);
            //leggi quale risposta ha dato il server ed in base ad essa scegli un dato da inviare
            //se la risposta del server e' 220 allora leggi lo user da tastiera ed inviala
            if(atoi(recvchar)==220)
            {
                //inserisci user e componi il buffer sendchar da inviare lungo il canale comandi
                inter_comandi(USER);
                //invia dal client al server tutti i byte in un colpo solo
                if(invia(sendchar, strlen(sendchar))==-1)
                {
                    break;   //se il ritorno e' -1 chiudi la socket
                    printf("\nErrore di invio: chiusura collegamento\n");
                }
                //altrimenti ritorna in modalita lettura per leggere la risposta
                else
                {
                    //azzera sendchar
                    sendchar[0]='\0';
                    continue;
                }
            }
            //se il server risponde con 331 inserisci la password ed invia
            if(atoi(recvchar)==331)
            {
                //inserisci password
                inter_comandi(PASS);
                //invia dal client al server tutti i byte in un colpo solo
                if(invia(sendchar, strlen(sendchar))==-1)
                {
                    break;   //se il ritorno e' -1 chiudi la socket
                    printf("\nErrore di invio: chiusura collegamento\n");
                }
                //altrimenti ritorna in modalita lettura per leggere la risposta
                else
                {
                    //azzera sendchar
                    sendchar[0]='\0';
                    continue;
                }
            }
            //se il server risponde con 440 reinserisci lo user ed invia
            if(atoi(recvchar)==440)
            {
                //reinserisci user
                inter_comandi(RUSER);
                //invia dal client al server tutti i byte in un colpo solo
                if(invia(sendchar, strlen(sendchar))==-1)
                {
                    break;   //se il ritorno e' -1 chiudi la socket
                    printf("\nErrore di invio: chiusura collegamento\n");
                }
                //altrimenti ritorna in modalita lettura per leggere la risposta
                else
                {
                    //azzera sendchar
                    sendchar[0]='\0';
                    continue;
                }
            }
            //se il server risponde con 400 reinserisci lo user ed invia
            if(atoi(recvchar)==400)
            {
                //reinserisci user
                inter_comandi(RUSER);
                //invia dal client al server tutti i byte in un colpo solo
                if(invia(sendchar, strlen(sendchar))==-1)
                {
                    break;   //se il ritorno e' -1 chiudi la socket
                    printf("\nErrore di invio: chiusura collegamento\n");
                }
                //altrimenti ritorna in modalita lettura per leggere la risposta
                else
                {
                    //azzera sendchar
                    sendchar[0]='\0';
                    continue;
                }
            }
            //se il server risponde con 221 esci dal ciclo per chiudere la connessione
            if(atoi(recvchar)==221)
            {
                break;
            }
            //se il server risponde con 430 reinserisci la password ed invia
            if(atoi(recvchar)==430)
            {
                //inserisci password
                inter_comandi(PASS);
                //invia dal client al server tutti i byte in un colpo solo
                if(invia(sendchar, strlen(sendchar))==-1)
                {
                    break;   //se il ritorno e' -1 chiudi la socket
                    printf("\nErrore di invio: chiusura collegamento\n");
                }
                //altrimenti ritorna in modalita lettura per leggere la risposta
                else
                {
                    //azzera sendchar
                    sendchar[0]='\0';
                    continue;
                }
            }
            //se il server risponde con 530 reinserisci la user e reinvia
            if(atoi(recvchar)==530)
            {
                //reinserisci user
                inter_comandi(RUSER);
                //invia dal client al server tutti i byte in un colpo solo
                if(invia(sendchar, strlen(sendchar))==-1)
                {
                    break;   //se il ritorno e' -1 chiudi la socket
                    printf("\nErrore di invio: chiusura collegamento\n");
                }
                //altrimenti ritorna in modalita lettura per leggere la risposta
                else
                {
                    //azzera sendchar
                    sendchar[0]='\0';
                    continue;
                }
            }
            //se ricevi il comando PORT seguito dal numero di porta
            if(com_server()==PORT)
            {
                //nel caso in cui e' stato battuto il comando "dir"
                if(en_send==LIST)
                {
                    //converti il numero di porta da stringa di char ad int
                    porta_dati=conv_chartoshort(recvchar);
                    //ripeti per due volte il ciclo di ricezione e stampa messaggi (risposta 200 e risposta 150)
                    for(x=0;x<2;x++)
                    {
                        //ricevi la risposta dal server e mettila in recvchar
                        if(ricevi(recvchar)==-1)     break;   //se il ritorno e' -1 chiudi la socket
                        //stampa il messaggio di ritorno in caso di numero porta ricevuto con successo
                        printf("\n%s",recvchar);
                    }
                    //crea socket
                    conn_sock_dati=creasocket(AF_INET, SOCK_STREAM, 0);
                    if(conn_sock_dati<0 )
                    {
                        fprintf(stderr,"Errore di apertura della socket dati: Error %d\n", errorp());
                        continue;
                    }
                    //e connettiti alla porta del canale dati
                    if(connectp(conn_sock_dati ,(struct sockaddr*)&server_dati, ADDRESS, AF_INET, porta_dati)==-1)
                    {
                        //se connectp() ritorna un errore
                        fprintf(stderr,"connessione col canale dati fallito: %d\n", errorp());
                        //e chiudi socket dati
                        closep(conn_sock_dati);
                    }
                    else
                    {
                        //ricevi il risultato del comando LIST dal canale dati
                        //e stampalo a monitor
                        if(caratteri_rx=ricevi_dati(PRINT)==-1)
                        {
                            closep(conn_sock_dati);   //chiudi il canale dati se hai riscontrato un problema di ricezione
                        }
                        else
                        {
                            //ricevi il numero di caratteri spediti e stampali
                            ricevi(recvchar);
                            caratteri_tx=atoi(recvchar);
                            printf("Numero di caratteri trasmessi: %d\n", caratteri_tx);
                            printf("Numero di caratteri ricevuti: %d\n", caratteri_rx);
                        }


                    }
                }
                //nel caso in cui e' stato battuto il comando "send"
                if(en_send==STOR)
                {

                }
                //nel caso in cui e' stato battuto il comando "recv"
                if(en_send==RECV)
                {

                }
            }
            //se ricevi il comando PATH seguito dal percorso attuale del filesystem remoto
            if(com_server()==PATH)
            {
                int x=0;
                //scorri lungo recvchar finche' trovi lo spazio
                while(recvchar[x++]!=' ');
            }
            //se dal server non viene ricevuto nessun messaggio con codice
            //mettiti in modalita' inserimento ed invio comando
            inter_comandi(COM);
            //invia dal client al server tutti i byte in un colpo solo
            //per inviare il comando al server
            if(invia(sendchar, strlen(sendchar))==-1)     break;   //se il ritorno e' -1 chiudi la socket
            //altrimenti ritorna in modalita lettura per leggere la risposta
            else
            {
                //azzera sendchar
                sendchar[0]='\0';
                continue;
            }
            if(retval==0)
            {
                printf("il server ha chiuso la connessione.\n");
                closep(conn_sock_com);
                WSACleanup();
                return -1;
            }
            printf("%c\n", recvchar[0]);
        }
        closep(conn_sock_com);
        WSACleanup();
        system("PAUSE");
        return 0;
    }








    //funzione per ricevere le risposte dal sever
    int ricevi(char *buffer)
    {
        int n_char;
        n_char=recvp(conn_sock_com, buffer, DEFAULT_BUFFER, 0);  //ricevi dal server tutti i byte in un colpo solo
        if(n_char==-1)
        {
            printf("recezione fallita: %d chiusura collegamento.\n", errorp());
            return -1;   //ritorna -1 per far chiudere la socket()
        }
        //inserisci il terminatore alla fine
        *(buffer+n_char)='\0';
        return n_char;
    }


    //funzione per inviare i comandi al server
    int invia(char *buffer, int len)
    {
        int n_char;
        n_char=sendp(conn_sock_com, buffer, len, 0);
        if(n_char==-1)
        {
            printf("invio fallito: %d chiusura collegamento.\n", errorp());
            return -1;
        }
        else return n_char;
    }


    //funzione di inserimento user
    void inserisci_user(void)
    {
        char Buffer[BUFFER];
        //metti il comando USER dentro a senchar
        strncpy(sendchar,"USER ",5);
        //leggi da tastiera la password
        scanf("%s", Buffer);
        //copia Buffer nella coda senchar
        strncpy((sendchar+5), Buffer, strlen(Buffer));
    }


    //funzione di inserimento password
    void inserisci_pass(void)
    {
        char Buffer[BUFFER];
        Buffer[0]='\0';
        int x=0;
        char carattere;
        //stampa a monitor "Password"
        printf("\nPassword:");
        //metti il comando PASS dentro a sendchar
        strncpy(sendchar,"PASS ",5);
        //leggi da tastiera la password con echo "*"
        while(carattere!='\r')
        {
            carattere=getch();
            strncat(Buffer, &carattere, 1);
            x++;
            printf("*");
        }
        Buffer[x]='\0';
        //copia Buffer nella coda senchar
        strncpy((sendchar+5), Buffer, strlen(Buffer));
    }



    //funzione di inserimento comandi
    void inserisci_comando(void)
    {
        char Buffer[BUFFER];
        char Buffer1[BUFFER];
        //leggi da tastiera il comando
        scanf("%s %s", Buffer, Buffer1);
        //aggiungi alla fine di Buffer uno spazio
        strncat(Buffer," ",strlen(" "));
        //accoda Buffer1 a Buffer
        strncat(Buffer, Buffer1, strlen(Buffer1));
        //copia Buffer in sendchar
        strncpy(sendchar, Buffer, strlen(Buffer));
        //metti ilterminatore alla fine del comando
        sendchar[strlen(Buffer)]='\0';
    }








    //funzione di interpretazione comandi ricevuti dalla tastiera ed inseriti in sendchar
    int comandi(void)
    {
        int x=0;
        char command[DEFAULT_BUFFER];
        //pulisci command
        command[0]='\0';
        //riempi command con i caratteri del comando contenuto in sendchar solo fino allo spazio di finecomando
        while(sendchar[x]!=' ')
        {
            strncat(command,&sendchar[x++],1);
        }
        if(strncmp(command,"cd ..",strlen("cd .."))==0)    return CDUP;
        if(strncmp(command,"cd",strlen("cd"))==0)          return CWD;
        if(strncmp(command,"rm",strlen("rm"))==0)          return RMD;
        if(strncmp(command,"del",strlen("del"))==0)        return DELE;
        if(strncmp(command,"help",strlen("help"))==0)      return HELP;
        if(strncmp(command,"dir",strlen("dir"))==0)        {en_send=LIST; return LIST;}
        if(strncmp(command,"mkdir",strlen("mkdir"))==0)    return MKD;
        if(strncmp(command,"quit",strlen("quit"))==0)      return QUIT;
        if(strncmp(command,"recv",strlen("recv"))==0)      {en_send=RETD; return RETD;}
        if(strncmp(command,"send",strlen("send"))==0)      {en_send=STOR; return STOR;}
        if(strncmp(command,"USER",strlen("USER"))==0)      return USER;
        if(strncmp(command,"user",strlen("user"))==0)      return USER;
        if(strncmp(command,"PASS",strlen("PASS"))==0)      return PASS;
        return 0;
    }



    //funzione di identificazione comando ricevuto dal server
    int com_server(void)
    {
        int x=0;
        char command[DEFAULT_BUFFER];
        //pulisci command
        command[0]='\0';
        //riempi command con i caratteri del comando contenuto in recvchar solo fino allo spazio di finecomando
        while(recvchar[x]!=' ')
        {
            strncat(command,&recvchar[x++],1);
        }
        if(strncmp(command,"PORT",strlen("PORT"))==0)    return PORT;
        if(strncmp(command,"PATH",strlen("PATH"))==0)    return PATH;
        return 0;
    }


    //funzione per la conversione da stringa a short
    u_short conv_chartoshort(char *recvchar)
    {
        int x=0;
        //scorri lungo recvchar finche' trovi lo spazio
        while(recvchar[x++]!=' ');
        return (u_short)atoi((recvchar+x));
    }


    //funzione di creazione sockets di ascolto
    SOCKET creasocket(int dominio, int tipo_socket, int protocollo)
    {
        return socket(dominio, tipo_socket, protocollo);
    }


    //funzione per connettersi ad un host
    int connectp(SOCKET sock, struct sockaddr_in *ind, char *addr, short dominio, u_short porta)
    {
        //rendi sockaddr_in uguale in dimensione a sockaddr
        memset((ind)->sin_zero, '\0', sizeof ind->sin_zero);
        //Impostazione di porta, indirizzo e tipo di socket con le conversioni da little endian a big endian
        (*ind).sin_addr.s_addr=inet_addr(addr);
        (*ind).sin_family=dominio;
        (*ind).sin_port=htons(porta);
        return connect(sock, (struct sockaddr *)ind, sizeof(*ind));
    }

    //funzione di chiusura socket
    int closep(SOCKET s)
    {
        return closesocket(s);
    }

    //funzione di ricezione caratteri
    int recvp(SOCKET s, char *buf, int len, int flags)
    {
        return recv(s, buf, len, flags);
    }

    //funzione di invio caratteri
    int sendp(SOCKET s, const char *buf, int len, int flags)
    {
        return send(s, buf, len, flags);
    }



    //funzione per ottenere l' ip in formato

        //se dalla chiamata ricevo un indirizzo per nome
        /*if (isalpha(server_name[0]))
        {
            //restituisci l' IP
            hp=gethostbyname(server_name);
        }
        //altrimenti se dalla chiamata arriva un IP in char
        else
        {
            //Converti l' IP in formato char in
            addr=inet_addr(server_name);
            hp=gethostbyaddr((char *)&addr, 4, AF_INET);
        }*/


    //questa funzione ha lo scopo di riceve
    //il file inviato dal server e stamparlo a monitor nel caso
    //sia passato a parametro la macro PRINT
    //nel caso ria passata RECV invecie salva il file nel percorso corrente con
    //lo stesso nome indicato nel percorso del parametro
    int ricevi_dati(int com)
    {
        int n_char=0;
        int caratteri;
        char Buffer[DEFAULT_BUFFER];   //buffer di servizio
        FILE *fp;
        if(com==PRINT)
        {
            do
            {
                caratteri=recvp(conn_sock_dati, Buffer, strlen(Buffer), 0);
                //inserisci il terminatore alla fine
                *(Buffer+caratteri)='\0';
                if(caratteri==-1)
                {
                    printf("recezione fallita: %d chiusura collegamento.\n", errorp());
                    return -1;   //ritorna -1 per far chiudere la socket()
                }
                printf("%s", Buffer);
                n_char=n_char+caratteri;
                //ricevi messaggio di conferma ricezione
                ricevi(Buffer);
            }while(atoi(Buffer)!=226);
        }
        //chiudi socket del canale dati
        closep(conn_sock_dati);
        return n_char;       //se non ci sono stati errori di invio ritorna il numero di caratteri ricevuti
    }


    //questa funzione funge da interprete dei comandi da tastiera
    //per poi convertirli in buffer da inviare lungo il canale comandi
    void inter_comandi(int com)
    {
        int cmd;
        do
        {
            if(com==USER)
            {
                inserisci_user();
            }
            if(com==PASS)
            {
                inserisci_pass();
            }
            if(com==RUSER)
            {
                inserisci_comando();
            }
            if(com==COM)
            {
                inserisci_comando();
            }
            //testa quale comando battuto da tastiera e' contenuto in sendchar
            cmd=comandi();
            switch(cmd)
            {
                //e componi la stinga comandi in sendchar da inviare in base al comando digitato
                case CDUP: componi_comando(CDUP);   return; break;
                case CWD:  componi_comando(CWD);    return; break;
                case RMD:  componi_comando(RMD);    return; break;
                case DELE:  componi_comando(DELE);  return; break;
                case HELP: componi_comando(HELP);   return; break;
                case LIST: componi_comando(LIST);   return; break;
                case MKD: componi_comando(MKD);     return; break;
                case QUIT:  componi_comando(QUIT);  return; break;
                case RETD: componi_comando(RETD);   return; break;
                case STOR: componi_comando(STOR);   return; break;
                case USER:  componi_comando(USER);  return; break;
                case PASS:  componi_comando(PASS);  return; break;
                default: printf("\nComando errato.\n");
            }
        }while(cmd==0);     //ripeti ciclo di inseriemnto finche' non viene difitato uno dei comandi sopra
    }


    //funzione di sostituzione del comando presente in sendchar
    //ricevuto da tastiera con il rispettivo comando del protocollo FTP
    void componi_comando(int com)
    {
        if(com==CDUP)
        {
            sostituisci("CDUP ", sizeof("CDUP "));
        }
        if(com==CWD)
        {
            sostituisci("CWD ", sizeof("CWD "));
        }
        if(com==RMD)
        {
            sostituisci("RMD ", sizeof("RMD "));
        }
        if(com==DELE)
        {
            sostituisci("DELE ", sizeof("DELE "));
        }
        if(com==HELP)
        {
            sostituisci("HELP ", sizeof("HELP "));
        }
        if(com==LIST)
        {
            sostituisci("LIST ", sizeof("LIST "));
        }
        if(com==MKD)
        {
            sostituisci("MKD ", sizeof("MKD "));
        }
        if(com==QUIT)
        {
            sostituisci("QUIT ", sizeof("QUIT "));
        }
        if(com==RETD)
        {
            sostituisci("RETD ", sizeof("RETD "));
        }
        if(com==STOR)
        {
            sostituisci("STOR ", sizeof("STOR "));
        }
        if(com==USER)
        {
            sostituisci("USER ", sizeof("USER "));
        }
        if(com==PASS)
        {
            sostituisci("PASS ", sizeof("PASS "));
        }
    }

    //funzione accessoria di componi_comando() per sostituire
    //i comandi da tastiera con i comandi FTP
    void sostituisci(char *FTP_com, int len)
    {
        int x=0;
        char command[DEFAULT_BUFFER];
        command[0]='\0';
        //spostati lungo sendchar finche' trovi lo spazio che divide il comando dal parametro
        while(sendchar[++x]!=' ');
        //copia il parametro contenuto in senchar nel buffer di servizio fino a fineparametro
        x++;
        while(sendchar[x]!='\0')
        {
            strncat(command, &sendchar[x++], 1);
        }
        //azzera sendchar
        sendchar[0]='\0';
        //metti in sendchar il comando FTP ricevuto da *FTP_com
        strncpy(sendchar, FTP_com, len);
        //ed attaccaci alla coda il parametro contenuto in command
        strncat(sendchar, command, strlen(command));
    }

    int errorp(void)
    {
        //se non e' stata inserita la macro 'LINUX' compila
        //riga sottostante
        #ifndef LINUX
        return WSAGetLastError();
        #else
        int errnum;
        strerror(errnum);
        return errnum;
        #endif
    }
Il codice del server lo posto in una risposta a questo post dato che in questo sono
gia' al limite dei caratteri massimi e quindi non ci sta.

La parte di codice del lato server deputata allo stampaggio dei risultatati
del comando dir (vedere http://www.tenouk.com/ModuleA1.htm)
l' ho modificata mettendo
caratteri=invia_dati(DIR, Buffer, 5);
al posto della printf() come da originale per poter inviare il risultato verso il client e non nello standard output del server.
Per favore datemi una mano perche' io ho dato forfe' perche' e' un pezzo
che ci sbatto la testa senza spiegarmi il perche' di tale comportamento

1 Risposte

  • Re: Problema di trasferimento sul canale dati con server c FTP

    Ecco il codice del server:
    //server FTP
    
    
        #include <winsock2.h>
        #include <windows.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include <io.h>
    
    
    
        #define DEFAULT_PORT       20
        #define DEFAULT_BUFFER      4096
        #define WIN32_LEAN_AND_MEAN
        #pragma comment(lib, "ws2_32.lib")
        //macro di identificazione comandi
        #define CDUP 1
        #define CWD 2
        #define RMD 3
        #define HELP 4
        #define MKD 5
        #define PWD 6
        #define QUIT 7
        #define RETD 8
        #define PASV 9
        #define DELE 10
        #define STOR 11
        #define USER 12
        #define PASS 13
        #define LIST 14
        //macro da passare alle varie funzioni
        #define PAR 22
        #define PATH 23
        #define DIR 24
        #define SEND 25
        //macro di disabilitazione ed abilitazione
        #define EN_OFF 20
        #define EN_ON 21
    
        //#define LINUX  //decommentare questa macro per compilare sotto linux
    
        //imposta il numero massimo di porte disponibili apribili per creare il canale dati
        #define RANGE_PORT 6
    
        int comandi(int percorso);
        int autentica(void);
        void help(void);
        void invio_risposta(int risposta);
        int reinserisci_user(void);
        int user_pass(char parametro);
        int apriporta(void);
        int invia_porta(int porta);
        int interpreta_com(void);
        int invio_comando(int comando);
        int apri_chdati(void);
        int invia_dati(int com, char *buf, int n);
        DWORD WINAPI servizio(LPVOID lpParam);
        DWORD WINAPI dir_curp(DWORD nBufferLength, LPTSTR lpBuffer);
        BOOL WINAPI mkdirp(LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
        BOOL WINAPI rmdirp(LPCTSTR lpPathName);
        BOOL WINAPI rmfilep(LPCTSTR lpFileName);
        //funzioni relative alla creazione, gestione socket e ricezione/invio
        SOCKET creasocket(int dominio, int tipo_socket, int protocollo);
        int bindp(SOCKET sock, struct sockaddr_in *ind,  u_long addr, short dominio, u_short porta);
        int ricevi(char *buffer);
        int invio(char *sendchar, int len);
        int listenp(SOCKET sock, int coda);
        SOCKET acceptp(SOCKET sock, struct sockaddr_in *client);
        int closep(SOCKET s);
        int recvp(SOCKET s, char *buf, int len, int flags);
        int sendp(SOCKET s, const char *buf, int len, int flags);
        int errorp(void);
    
    
        //buffers di ricezione ed invio comandi e risposte
        char recvchar[DEFAULT_BUFFER];
        char sendchar[128];
    
        //range di porte apribili sul canale dati del server
        int range_porte[RANGE_PORT]={3267,3268,3269,3270,3271,3272};
        //int range_porte[RANGE_PORT]={20,21};
        char szAddress[128];       //Interfacccia di ascolto
        //dichiarazione sockets
        SOCKET socketdati, socketdati1, socketdati2, socketascolto1, socketascolto2;
        WSADATA       wsd;
        HANDLE        nuovo_proc_figlio;
        DWORD         IDThread;
        struct sockaddr_in local, localdati, client, clientdati;
        //variabile di abilitazione ricezione/spedizione file sul canale dati
        int en_send;
        //dichiaro un buffer per contenere il percorso corrente
        char path_DIR[200];
        //dichiaro un buffer per contenere il percorso in cui mettere il file del comando dir
        char pathdir[200];
        //buffer di servizio contenente il valore del percorso ricevuto
        char parametro[128];
    
        int main(int argc, char **argv)
        {
            //variabile di gestione degli errori
            int error;
            //ottieni array del percorso corrente
            dir_curp(200, path_DIR);
            //attacca alla coda di path_DIR il nome della directory da creare
            strncat(path_DIR,"\\FTP\\",7);
            //crea la directory "FTP" dentro il path del binario del server
            mkdirp(path_DIR,NULL);
            //se il caricamento di WSAStartup fallisce chiudi l' applicazione
            if(WSAStartup(MAKEWORD(2,2), &wsd) != 0)
            {
                return 1;
            }
            //crea socket di ascolto di tipo STREAM del dominio AF_INET
            socketascolto1=creasocket(AF_INET, SOCK_STREAM, IPPROTO_IP);
            if(socketascolto1==-1)
            {
                //se fallisce la creazione della socket chiudi
                WSACleanup();
                return 1;
            }
            //effettua il binding sulla porta 21 con l' indirizzo della eth0 locale
            error=bindp(socketascolto1, &local, INADDR_ANY, AF_INET, DEFAULT_PORT);
            if(error==-1)
            {
                //se fallisce il binding sulla porta chiudi
                closep(socketascolto1);
                WSACleanup();
                return 1;
            }
            //metti la socket creata in ascolto per creare una coda massima di due richieste client
            error=listenp(socketascolto1,2);
            if(error==-1)
            {
                //se fallisce listenp chiudi
                closep(socketascolto1);
                WSACleanup();
                return -1;
            }
            //questo ciclo aspetta continuamente le connessioni dai client
            //quando un client si connette vien creato un Thread
            //che chiama la funzione servizio che serve appunto a gestire il dialogo
            //tra client e server
            while(1)
            {
                socketdati1=acceptp(socketascolto1, &client);
                if(socketdati1==INVALID_SOCKET)
                {
                    closep(socketdati1);
                    continue;
                }
                //inet_ntoa(client.sin_addr), ntohs(client.sin_port));
                nuovo_proc_figlio=CreateThread(NULL, 0, servizio,
                (LPVOID)socketdati1, 0, &IDThread);
                if (nuovo_proc_figlio==NULL)
                {
                    //se la creazione del processo
                    //figlio non ha avuto successo chiudi il thread
                    //chiudi la socket di ascolto e chiudi il programma
                    break;
                }
                CloseHandle(nuovo_proc_figlio);
            }
            closep(socketascolto1);
            WSACleanup();
            return 0;
        }
    
    
    
    
    
        //Funzione servizio:
        //Questa funzione e' un thread che gestisce il servizio FTP una volta
        //ottenuta una connessione  con accept()
        //Il parametro passato e' l'handle della socket
        //ritornato dalla chiaamta accept().
        //Questa funzione gestisce l' interazione tra client e server
        DWORD WINAPI servizio(LPVOID lpParam)
        {
            socketdati=(SOCKET)lpParam;
            //abilita invio/ricezione sul canale dati
            en_send=EN_ON;
            while(1)
            {
                //invio risposta di presentazione
                invio_risposta(220);
                //se la send() la recv() danno errori di ricezione o trasmissione chiudi la socket
                //per rimanere in attesa di una nuova richiesta dal client
                if(autentica()==1)
                {
                    //invia risposta di disconnessione, chiudi sockets del processo figlio ed esci
                    invio_risposta(221);
                    closep(socketdati);
                    closep(socketdati1);
                    //e chiudi thread
                    return 0;
                }
                //se la funzione di gestione dei comandi ritorna 1 ritorna 0
                //in modo da far chiudere il processo figlio
                //questa funzione serve a gestire il servizio ricevendo ed interpretando i comandi del client
                if(interpreta_com()==1)
                {
                    //invia risposta di disconnessione, chiudi sockets del processo figlio ed esci
                    invio_risposta(221);
                    closep(socketdati);
                    closep(socketdati1);
                    closep(socketdati2);
                    closep(socketascolto2);
                    return 0;
                }
            }
            return 0;
        }
    
    
    
        //funzione di interpretazione comandi presenti in recvchar
        //se nel parametro viena passato 0 viene estratto e ritornato il contenuto della
        //macro del comando se invecie viene dato come argomento la macro "PAR" viene salvato in un buffer
        //globale il parametro in questione
        int comandi(int percorso)
        {
            int x=0;
            char command[DEFAULT_BUFFER];
            //pulisci command
            command[0]='\0';
            //riempi command con i caratteri del comando contenuto in recvchar solo fino allo spazio di finecomando
            while(recvchar[x]!=' ')
            {
                strncat(command,&recvchar[x++],1);
            }
            if(percorso==PAR)
            {
                x++;
                //trasferisci in parametro il contenuto del parametro di recvchar
                while(recvchar[x]!='\0')
                {
                    strncat(parametro, &recvchar[x++],1);
                }
                return 0;
            }
            if(strncmp(command,"CDUP",strlen("CDUP"))==0)    return CDUP;
            if(strncmp(command,"CWD",strlen("CWD"))==0)      return CWD;
            if(strncmp(command,"RMD",strlen("RMD"))==0)      return RMD;
            if(strncmp(command,"DELE",strlen("DELE"))==0)    return DELE;
            if(strncmp(command,"HELP",strlen("HELP"))==0)    return HELP;
            if(strncmp(command,"LIST",strlen("LIST"))==0)    return LIST;
            if(strncmp(command,"MKD",strlen("MKD"))==0)      return MKD;
            if(strncmp(command,"QUIT",strlen("QUIT"))==0)    return QUIT;
            if(strncmp(command,"RETD",strlen("RETD"))==0)    return RETD;
            if(strncmp(command,"PASV",strlen("PASV"))==0)    return PASV;
            if(strncmp(command,"STOR",strlen("STOR"))==0)    return STOR;
            if(strncmp(command,"user",strlen("user"))==0)    return USER;
            if(strncmp(command,"USER",strlen("USER"))==0)    return USER;
            if(strncmp(command,"pass",strlen("pass"))==0)    return PASS;
            if(strncmp(command,"PASS",strlen("PASS"))==0)    return PASS;
            return 0;
        }
    
    
    
    
    
    
    
    
    
        //funzione di abilitazione dell' autenticazione
        int autentica(void)
        {
            int rit1=1;
            int ritorno;
            int risultato;
            //ciclo di ricezione user
            //ripeti finche' la user e' corretta
            while(risultato!=331)
            {
                if(ricevi(recvchar)==-1)   return 1;    //se ricevi ha un errore di ricezione ritorna 1 in modo che autentica chiuda la socket
                //chiama funzione di controllo esattezza user ('u')
                rit1=user_pass('u');
                //se la user e' giusta
                if(rit1==15)
                {
                    //invia messaggio di user esatta
                    invio_risposta(331);
                    //metti risultato a 331 in modo da uscire dal ciclo di ins. user
                    risultato=331;
                }
                //se la user e' errata
                if(rit1==17)
                {
                    //invia messaggio di user errata
                    invio_risposta(531);
                    risultato=531;
                    //ricevi comando
                    ritorno=reinserisci_user();
                    //testa se sono stati ricevuti QUIT, USER o HELP
                    switch(ritorno)
                    {
                        //se reinserisci() riceve il comando QUIT ritorna 1 per far chiudere la connessione
                        case 1:  return 1;  break;
                        //se e' stato inserito il comando USER testa l' esattezza della user
                        case 15:
                        {
                            //testa correttezza della user
                            ritorno=user_pass('u');
                            //se e' corretta
                            if(ritorno==15)
                            {
                                //invia messaggio di user esatta
                                invio_risposta(331);
                                risultato=331;
                            }
                            else
                            {
                                //invia messaggio di user errata
                                invio_risposta(531);
                                risultato=531;
                            }
                        }
                        break;
                    }
                }
            }
            while(risultato!=230)
            {
                if(ricevi(recvchar)==-1)   return 1;    //se ricevi ha un errore di ricezione ritorna 1 in modo che autentica chiuda la socket
                //chiama funzione di controllo esattezza password ('p')
                rit1=user_pass('p');
                //se la password e' giusta
                if(rit1==15)
                {
                    //invia messaggio di password esatta
                    invio_risposta(230);
                    //metti risultato a 230 in modo da uscire dal ciclo di ins. password
                    risultato=230;
                }
                //se la password e' errata
                if(rit1==17)
                {
                    //invia messaggio di login non avvenuto
                    invio_risposta(530);
                    risultato=530;
                    //ricevi comando
                    ritorno=reinserisci_user();
                    //testa se sono stati ricevuti QUIT, USER o HELP
                    switch(ritorno)
                    {
                        //se reinserisci() riceve il comando QUIT ritorna 1 per far chiudere la connessione
                        case 1:  return 1;  break;
                        //se e' stato inserito il comando USER
                        case 15:
                        {
                            //testa correttezza della user
                            ritorno=user_pass('u');
                            //se e' corretta
                            if(ritorno==15)
                            {
                                //invia messaggio di user esatta
                                invio_risposta(331);
                                risultato=331;
                            }
                            else
                            {
                                //invia messaggio di user errata
                                invio_risposta(531);
                                risultato=531;  //metti risultato a 531 per far ritornare all' inizio e ripetere il reinserimento user
                            }
                        }
                        break;
                        //se e' stato inserito il coamando PASS
                        case 20:
                        {
                            //testa la correttezza della password
                            ritorno=user_pass('p');
                            //se e' corretta
                            if(ritorno==15)
                            {
                                //invia messaggio di password esatta
                                invio_risposta(230);
                                //metti risultato a 230 in modo da uscire dal ciclo di ins. password
                                ritorno=331;
                                risultato=230;
                            }
                            //se la password e' errata
                            else if(ritorno==17)
                            {
                                invio_risposta(530);
                                ritorno=530;
                            }
                        }
                        break;
                    }
                }
            }
            return 0;
        }
    
        //funzione di invio comandi
        void help(void)
        {
            sendp(socketdati,"\n\rcd    cd..  rm   help   mkdir\n\r",strlen("\n\rcd    cd..  rm   help   mkdir\n\r"),0);
            sendp(socketdati,"\n\rpwd   quit  recv passv  rmdir\n\r",strlen("\n\rpwd   quit  recv passv  rmdir\n\r"),0);
            sendp(socketdati,"\n\rsend user  pass ls\n\r",strlen("\n\rsend user  pass ls\n\r"),0);
        }
    
    
        //funzione per l' invio delle risposte al client
        void invio_risposta(int risposta)
        {
            switch(risposta)
            {
                case 530:
                {
                     strncpy(sendchar,"530 Not logged in\n\r",21);
                     invio(sendchar, 21);
                     strncpy(sendchar,"User non valida\n\r",19);
                     invio(sendchar, 19);
                     break;
                }
                case 531:
                {
                    strncpy(sendchar,"530 Invalid user name\n\r",25);
                    invio(sendchar, 25);
                    strncpy(sendchar,"Accesso non riuscito\n\r",25);
                    invio(sendchar, 25);
                    break;
                }
                case 220:
                {
                    strncpy(sendchar,"\n220 Server ftp FTP\r\nUser:",30);
                    //send(socketdati, sendchar, sizeof(sendchar), 0);
                    invio(sendchar, 30);
                    break;
                }
                case 221:
                {
                    strncpy(sendchar,"221 Good bye, closing session.\n\r",35);
                    invio(sendchar, 35);
                    break;
                }
                case 226:
                {
                    strncpy(sendchar,"226 Transfer complete.",22);
                    invio(sendchar, 22);
                    break;
                }
                case 200:
                {
                    strncpy(sendchar,"200 PORT command successfull.\n\r",32);
                    invio(sendchar, 32);
                    break;
                }
                case 400:
                {
                    strncpy(sendchar,"400 Unknow command\n\r",23);
                    invio(sendchar, 23);
                    break;
                }
                case 331:
                {
                    strncpy(sendchar,"331 User required for gianni\n\r",33);
                    invio(sendchar, 33);
                    break;
                }
                case 230:
                {
                    strncpy(sendchar,"230 Welcome\n\r",16);
                    invio(sendchar, 16);
                    break;
                }
                case 150:
                {
                    strncpy(sendchar,"150 Opening ASCII mode data channel connection.\n\r",50);
                    invio(sendchar, 50);
                    break;
                }
                case 426:
                {
                    strncpy(sendchar,"426 impossibile aprire il canale dati\n\r",40);
                    invio(sendchar, 40);
                    break;
                }
                case 100:
                {
                    strncpy(sendchar,"100\n\r",7);
                    invio(sendchar, 7);
                    break;
                }
            }
        }
    
    
        //funzione di reinserimento della user
        int reinserisci_user(void)
        {
            //ciclo per testare se e' stato inserito user, help o quit
            while(1)
            {
                //se ricevi ritorna un errore ritorna 1 da autentica() in modo che chiuda la socket
                if(ricevi(recvchar)==-1)     return 1;
                //verifica il comando dato
                switch(comandi(0))
                {
                    //se il comando ricevuto e' user
                    case USER: return 15; break;
                    //se il comando contenuto in recvchar e' help invia la lista di comandi disponibili
                    //al client e ritorna all' inizio e ripeti richiesta comandi
                    case HELP:
                    {
                        help();
                        continue;
                    }
                    break;
                    //se il comando contenuto in recvchar e' quit ritorna solo 0
                    case QUIT:
                    {
                        //ritorna 1 per far disconnettere la socket ad autentica()
                        return 1;
                    }
                    break;
                    //se e' stata inserita la password
                    case PASS:
                    {
                        return 20;  //ritorna 20 per indicare che nel comando c'e' la voce PASS
                    }
                    break;
                    default: invio_risposta(400);     //invio comando errato
                }
            }
        }
    
    
    
        //funzione di test esattezza user o password
        int user_pass(char parametro)
        {
            int x=0, rit1=1, rit2=1;
            char command[200];
            //pulisci command
            command[0]='\0';
            //spostati lungo recvchar finche arrivi allo spazio
            while(recvchar[x++]!=' '){};
            //riempi command con i caratteri del parametro contenuto in recvchar
            //fino alla fine del buffer
            do
            {
                strncat(command,&recvchar[x++],1);
            }while(recvchar[x]!='\0');
            strncat(command,&recvchar[x],1);   //attaccaci alla fine il terminatore
            //testa l'esattezza della user
            switch(parametro)
            {
                // 'u' sta per user se l' argomento passato e' u testa la user
                case 'u':
                {
                    rit1=strncmp(recvchar,"user gianni",strlen("user gianni"));
                    rit2=strncmp(recvchar,"USER gianni",strlen("USER gianni"));
                }
                break;
                //  'p' sta per password se l' argomento passato e' p testa la password
                case 'p':
                {
                    rit1=strncmp(recvchar,"pass aaaaaaaa",strlen("pass aaaaaaaa"));
                    rit2=strncmp(recvchar,"PASS aaaaaaaa",strlen("PASS aaaaaaaa"));
                }
                break;
            }
            if(rit1==0 || rit2==0)    return 15;  //se la user o la password sono giuste ritorna 15
            else return 17;            //altrimenti 17
        }
    
    
    
    
    
    
    
        //funzione di apertura porte canale dati
        //che ritorna il numero decimale della porta aperta
        int apriporta(void)
        {
            int error, x=0;
            do
            {
                if(WSAStartup(MAKEWORD(2,2), &wsd) != 0)
                {
                    return 1;
                }
                //crea socket di ascolto di tipo STREAM del dominio AF_INET
                socketascolto2=creasocket(AF_INET, SOCK_STREAM, IPPROTO_IP);
                if(socketascolto2==-1)
                {
                    closep(socketascolto2);
                }
                //effettua il binding su un range di porte con l' indirizzo della eth0 locale
                //finche trovi una porta non bindata
                error=bindp(socketascolto2, &local, INADDR_ANY, AF_INET, range_porte[x++]);
                if(error==-1)
                {
                    closep(socketascolto2);
                }
            }while(errorp()==WSAEADDRINUSE && x<RANGE_PORT);
            if(error==0)
            {
                //metti la socket creata in ascolto per creare una coda massima di due richieste client
                error=listenp(socketascolto2,2);
                if(error==-1)
                {
                    //se la listenp() falllisce chiudi la nuova socket di ascolto ed esci
                    closep(socketascolto2);
                    return 1;
                }
                //altrimenti ritorna il numero di porta in valore decimale
                else return   range_porte[--x];   //se l'ultima porta bindata e' libera ritorna il numero della porta convertito in decimale
            }
            else
            {
                //chiudi socket di ascolto canale dati
                closep(socketascolto2);
                return 1;              //e ritorna 1
            }
        }
    
        //funzione di invio valore della porta dati aperta dal server
        int invia_porta(int porta)
        {
            int n_char;
            //dichiara buffer di servizio
            char buffer[1024];
            strncpy(sendchar,"PORT ",5);
            //aggiungi il \0 alla fine di sendchar
            sendchar[5]='\0';
            //converti il valore della porta da int a stringa di char
            itoa(porta, buffer, 10);
            //attaccaci '\n\r\0'
            strncat(buffer, "\n\r\0", strlen("\n\r\0"));
            //attacca la stringa delle cifre della porta alla coda del comando PORT
            strncat(sendchar,buffer, 7);
            //se la spedizione del numero di porta al client da un errore ritorna 0
            n_char=invio(sendchar, 12);
            if(n_char==-1)   return 0;
            //altrimenti ritorna il numero di caratteri inviati
            else return n_char;
        }
    
    
    
    
    
    
    
    
    
    
    
        //funzione per la richiesta di ricezione dei comandi dal client
        int ricevi(char *buffer)
        {
            int n_char;
            n_char=recvp(socketdati, buffer, sizeof(recvchar), 0);  //ricevi dal client tutti i byte in un colpo solo
            //se ottengo un errore nella recv() ritorna 1 per chiudere al socket()
            if(n_char==-1)
            {
                return -1;
            }
            *(buffer+n_char)='\0';
            return n_char;
        }
    
    
        //funzione di invio risposte
        int invio(char *sendchar, int len)
        {
            int n_char;
            n_char=sendp(socketdati, sendchar, len, 0);
            if(n_char==-1)
            {
                return -1;
            }
            else return n_char;
        }
    
    
        //funzione di creazione sockets di ascolto
        SOCKET creasocket(int dominio, int tipo_socket, int protocollo)
        {
            return socket(dominio, tipo_socket, protocollo);
        }
    
    
    
        //funzione di binding della porta
        int bindp(SOCKET sock, struct sockaddr_in *ind, u_long addr, short dominio, u_short porta)
        {
            //rendi sockaddr_in uguale in dimensione a sockaddr
            memset((ind)->sin_zero, '\0', sizeof ind->sin_zero);
            //Impostazione di porta, indirizzo e tipo di socket con le conversioni da little endian a big endian
            (*ind).sin_addr.s_addr=htonl(addr);
            (*ind).sin_family=dominio;
            (*ind).sin_port=htons(porta);
            return bind(sock, (struct sockaddr *)ind, sizeof(*ind));
        }
    
        //funzione di listening
        int listenp(SOCKET sock, int coda)
        {
            return listen(sock, coda);
        }
    
        //funzione di accettazione delle connessioni in coda
        SOCKET acceptp(SOCKET sock,  struct sockaddr_in *client)
        {
            //ottieni la dimensione dell' istanza client
            int Size=sizeof(*client);
            return accept(sock, (struct sockaddr*)&client, &Size);
        }
    
        //funzione di chiusura socket
        int closep(SOCKET s)
        {
            return closesocket(s);
        }
    
        //funzione di ricezione caratteri
        int recvp(SOCKET s, char *buf, int len, int flags)
        {
            return recv(s, buf, len, flags);
        }
    
        //funzione di invio caratteri
        int sendp(SOCKET s, const char *buf, int len, int flags)
        {
            return send(s, buf, len, flags);
        }
    
    
    
        //funzione per dare il percorso corrente
        DWORD WINAPI dir_curp(DWORD nBufferLength, LPTSTR lpBuffer)
        {
            return GetCurrentDirectory(nBufferLength, lpBuffer);
        }
    
    
        //funzione per creare una directory
        BOOL WINAPI mkdirp(LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
        {
            return CreateDirectory(lpPathName, lpSecurityAttributes);
        }
    
    
        //funzione rimuovere una directory
        BOOL WINAPI rmdirp(LPCTSTR lpPathName)
        {
             return RemoveDirectory(lpPathName);
        }
    
    
        //funzione per cacellare un file
        BOOL WINAPI rmfilep(LPCTSTR lpFileName)
        {
            return DeleteFile(lpFileName);
        }
    
    
        //funzione principale di lettura decodifica ed esecuzione comandi
        int interpreta_com(void)
        {
            //ripeti ciclo di lettura dei comandi provenienti dal canale comandi
            //finche' ricevi il comando QUIT che fara' rompere il ciclo
            //ed uscire dal processo figlio
            while(1)
            {
                //rimani in attesa dei comandi
                if(ricevi(recvchar)==-1)
                {
                    //e chiudi thread
                    return 1;
                }
                //testo il valore restituito da comando() ed in base alla macro del comando restituito
                //chiamo la funzione specifica che esegue il comando voluto dal client
                //tale funzione controllera' se la rimanente parte di Buffer ossia quella
                //che contiene il parametro del comando contiene un parametro corretto o meno
                //ed in base a questo invio con una send() la risposta affermativa o no al client
                //se il parametro e' accettabile esegue il comando altriemnti invia un messaggio
                //di errore al client
                switch(comandi(0))
                {
                    case HELP:
                    {
                        //se ricevi il coamndo HELP chiama la funzione di invio comandi disponibili
                        help();
                    }
                    break;
                    case QUIT:
                    {
                        return 1;
                    }
                    break;
                    case CWD:
                    {
                        //se ricevi il comando cd (cambia directory)
                        chdir(recvchar);
                    }
                    break;
                    case LIST:
                    {
                        //se e' impossibile aprire il canale dati ricevi comando sucessivo
                        if(apri_chdati()==1)    continue;
                        //invia percorso attuale nel server
                        invio_comando(LIST);
                    }
                    break;
                }
            }
        }
    
        //funzione di invio percorso attuale e contenuto delle directory
        int invio_comando(int comando)
        {
            char Buffer[260];   //buffer di servizio
            int n_char=0;
            int caratteri;
            if(comando==PATH)
            {
                //riempi la stringa comando con PATH seguita dal percorso attuale
                strncpy(Buffer, "PATH ",5);
                strncat(Buffer, path_DIR, strlen(path_DIR));
                strncpy(sendchar, Buffer, strlen(Buffer));
                //invia il comando ottenuto in sendchar
                invio(sendchar, strlen(sendchar));
            }
            if(comando==LIST)
            {
                //estrai dal buffer recvchar ricevuto dal client il parametro del percorso se c'e'
                //e mettilo in parametro
                comandi(PAR);
                //se il primo carattere e' uno 0 non attaccarlo alla cosa del percorso
                if(parametro[0]!='0')
                {
                    //se nel primo carattere c'e' la lettera del drive C copia il percorso inviato in path_DIR
                    if(parametro[0]=='C' || parametro[0]=='c')      strncpy(path_DIR, parametro, strlen(parametro));
                    //altrimenti aggiungi al percorso attuale il percorso indicato dall' utente
                    else strncat(path_DIR, parametro, strlen(parametro));
                }
                struct _finddata_t c_file;
                long   hFile;
                if(_chdir(path_DIR))
                {
                    invio("The Folder don't exist", sizeof("The Folder don't exist"));
                    return -1;
                }
                //cerca prima nella directory corrente
                //hFile=(long) _findfirst("*.*", &c_file);
                hFile=_findfirst("*.*", &c_file);
                //lista dei files
                caratteri=invia_dati(DIR, "\nRDO SYS HID ARC  FILE\t\t\tSIZE\n\r", sizeof("\nRDO SYS HID ARC  FILE\t\t\tSIZE\n\r"));
                invio_risposta(100);      //ad ogni invio di un buffer sul canale dati invio un messaggio di conferma sul canale comandi
                n_char=n_char+caratteri;
                caratteri=invia_dati(DIR, "---- --- --- ---  ----\t\t\t----\n\r", sizeof("---- --- --- ---  ----\t\t\t----\n\r"));
                invio_risposta(100);
                n_char=n_char+caratteri;
                if((c_file.attrib & _A_RDONLY))    strncpy(Buffer, " Y  ", sizeof(" Y  "));
                else   strncpy(Buffer, " N  ", sizeof(" N  "));
                caratteri=invia_dati(DIR, Buffer, 5);
                invio_risposta(100);
                n_char=n_char+caratteri;
                if((c_file.attrib & _A_RDONLY))    strncpy(Buffer, " Y  ", sizeof(" Y  "));
                else   strncpy(Buffer, " N  ", sizeof(" N  "));
                caratteri=invia_dati(DIR, Buffer, 5);
                invio_risposta(100);
                n_char=n_char+caratteri;
                if((c_file.attrib & _A_RDONLY))    strncpy(Buffer, " Y  ", sizeof(" Y  "));
                else   strncpy(Buffer, " N  ", sizeof(" N  "));
                caratteri=invia_dati(DIR, Buffer, 5);
                invio_risposta(100);
                n_char=n_char+caratteri;
                if((c_file.attrib & _A_RDONLY))    strncpy(Buffer, " Y  ", sizeof(" Y  "));
                else   strncpy(Buffer, " N  ", sizeof(" N  "));
                caratteri=invia_dati(DIR, Buffer, 5);
                invio_risposta(100);
                strncpy(Buffer, c_file.name, strlen(c_file.name));
                Buffer[strlen(c_file.name)]='\0';
                strncat(Buffer, "\t\t\t", sizeof("\t\t\t"));
                //invia il nome del file staccato da 3 tabulazioni
                n_char=n_char+caratteri;
                caratteri=invia_dati(DIR, Buffer, strlen(Buffer));
                invio_risposta(100);
                //e converti da long a stringa le dimensioni ed inviale sul canale dati
                snprintf(Buffer, sizeof(Buffer), "%ld\n\r", c_file.size);
                strncat(Buffer, "\n\r", sizeof("\n\r"));
                n_char=n_char+caratteri;
                caratteri=invia_dati(DIR, Buffer, strlen(Buffer));
                invio_risposta(100);
                //cerca il resto dei files
                while(_findnext(hFile, &c_file) == 0)
                {
                    if((c_file.attrib & _A_RDONLY))    strncpy(Buffer, " Y  ", sizeof(" Y  "));
                    else   strncpy(Buffer, " N  ", sizeof(" N  "));
                    n_char=n_char+caratteri;
                    caratteri=invia_dati(DIR, Buffer, 5);
                    invio_risposta(100);
                    if((c_file.attrib & _A_RDONLY))    strncpy(Buffer, " Y  ", sizeof(" Y  "));
                    else   strncpy(Buffer, " N  ", sizeof(" N  "));
                    n_char=n_char+caratteri;
                    caratteri=invia_dati(DIR, Buffer, 5);
                    invio_risposta(100);
                    if((c_file.attrib & _A_RDONLY))    strncpy(Buffer, " Y  ", sizeof(" Y  "));
                    else   strncpy(Buffer, " N  ", sizeof(" N  "));
                    n_char=n_char+caratteri;
                    caratteri=invia_dati(DIR, Buffer, 5);
                    invio_risposta(100);
                    if((c_file.attrib & _A_RDONLY))    strncpy(Buffer, " Y  ", sizeof(" Y  "));
                    else   strncpy(Buffer, " N  ", sizeof(" N  "));
                    n_char=n_char+caratteri;
                    caratteri=invia_dati(DIR, Buffer, 5);
                    invio_risposta(100);
                    strncpy(Buffer, c_file.name, strlen(c_file.name));
                    strncat(Buffer, "\t\t\t", sizeof("\t\t\t"));
                    //invia il nome del file staccato da 3 tabulazioni
                    n_char=n_char+caratteri;
                    caratteri=invia_dati(DIR, Buffer, strlen(Buffer));
                    invio_risposta(100);
                    //e converti da long a stringa le dimensioni ed inviale sul canale dati
                    snprintf(Buffer, sizeof(Buffer), "%ld\n\r", c_file.size);
                    strncat(Buffer, "\n\r", sizeof("\n\r"));
                    n_char=n_char+caratteri;
                    caratteri=invia_dati(DIR, Buffer, strlen(Buffer));
                    invio_risposta(100);
                }
                _findclose(hFile);
                //invio messaggio di trasferimento file completato
                invio_risposta(226);
                //converti il numero di caratteri inviati da int a buffer di char
                itoa(n_char, Buffer, 10);
                //invia il numero di caratteri spediti sul canale comandi
                invio(Buffer, strlen(Buffer));
                //ritorna il numero di caratteri spediti
                return n_char;
            }
        }
    
    
        //questa funzione ha lo scopo di aprire il canale dati
        //se il canale dati non viene stabilito ritorna 1 altrimenti 0
        int apri_chdati(void)
        {
            //se ricevi il comando LIST
            //tenta di aprire una porta per creare un canale dati
            int porta=apriporta();
            //se il tentativo di apertura porta e' fallito
            if(porta==1)
            {
                //invia risposta di impossibilita' di aprire la porta dati
                invio_risposta(426);
                //chiudi socket di ascolto per il canale dati
                closep(socketdati2);
                //disabilita invio/ricezione sul canale dati
                en_send=EN_OFF;
                //ricevi il prossimo comando
                return 1;
            }
            //altrimenti se la porta dati e' stata aperta invia il numero di porta dati al client
            else
            {
                //abilita le funzioni LIST STOR e RETD
                en_send=EN_ON;
                //se invia_porta() ritorna un errore
                if(invia_porta(porta)==0)
                {
                    //invia risposta di impossibilita' di aprire il canale dati
                    invio_risposta(426);
                    //chiudi socket di ascolto del canale dati
                    closep(socketascolto2);
                    //disabilita invio/ricezione sul canale dati
                    en_send=EN_OFF;
                    return 1;
                }
                //altrimenti invia risposta di invio comando PORT riuscito
                else
                {
                    //abilita invio/ricezione sul canale dati
                    en_send=EN_ON;
                    //invio messaggio di successo invio porta dati
                    invio_risposta(200);
                }
                //invia messaggio di apertura del canale dati
                invio_risposta(150);
                socketdati2=acceptp(socketascolto2, &clientdati);
                //se la messa in ascolto della socket dati ritorna errore
                if(socketdati2==INVALID_SOCKET)
                {
                    //invia sul canale comandi il messaggio di
                    //impossibilita' di aprire il canale dati
                    invio_risposta(426);
                    //chiudi le socket di ascolto e dati del canale dati
                    closep(socketdati2);
                    closep(socketascolto2);
                    en_send=EN_OFF;
                    return 1;
                }
                else
                {
                    //abilita invio/ricezione sul canale dati
                    en_send=EN_ON;
                    return 0;
                }
            }
        }
    
    
        //funzione di invio file lungo il canale dati
        //essa ritorna il numero di caratteri inviati
        int invia_dati(int com, char *buf, int n)
        {
            int n_char=0;
            FILE *fp;
            if(com==DIR)
            {
                n_char=sendp(socketdati2, buf, n, 0);
                if(n_char==-1)
                {
                    closep(socketdati2);    //chiudi la socket del canale dati
                    closep(socketascolto2); //chiudi la socket di ascolto del canale dati
                    return -1;    //se c'e' stato un errore di invio ritorna -1 per poter chiudere la socket del canale dati
                }
                return n_char;            //se non ci sono stati errori di invio ritorna il numero di caratteri inviati
            }
            if(com==SEND)
            {
    
            }
        }
    
    
        int errorp(void)
        {
            //se non e' stata inserita la macro 'LINUX' compila
            //riga sottostante
            #ifndef LINUX
            return WSAGetLastError();
            #else
            int errnum;
            strerror(errnum);
            return errnum;
            #endif
        }
    
    
    
Devi accedere o registrarti per scrivere nel forum
1 risposte