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
}