I'm trying to make a simple FTP client/server in C under Linux. I wrote almost everything but I have a strange bug somewhere

I'll explain in shortly what is my implementation:
So I have a simple client, it can list directories, change directories, get/put files etc ... the basic commands.
First of all it connects to the server, logs into his "home" dir and after that it waits for user's commands.
That's all for the client, you can see the details in the source that I'll provide here.
At the other side is the server. He listens always on a specified port if there is some client trying to connect. When a client is present the connection is established and the server is ready for the user's commands.
I decided to make server in a such way that when there is a client that wants to make a simple command like "cd" or "pwd" this is the server process who is executing it. But if there is a command like a "put" or "get" the server creates a process (fork()) and passes the execution of this command to the child.
When the user wants to make "get", "put" or "dir" I decided also to make a second TCP connection between the server and the client (server -> client), dedicated only for the data transfer, in this way the first connection is available for other commands.
I inspired myself for this decision looking at the FTP rfc.
You can also look at the code and see how the things are.
Now, to my problem

So when I'm making simple commands that doesn't require a process to be forked everything goes OK. But when I'm making some "dir" or "put" for example it doesn't work every time.
I saw that there is some problem when the server tries to connect to the client when I'm using this kind of commands. (exec_comm.c file contains that). The client refuses to accept the connection from the server
. And I can't understand why ... I'm sure that there is a bug in my code, but I'm not so good to find it by my self 
So if you have some ideas or remarks feel free to post it here

Thank you very much in advance.
Best regards,
Tonio
The client code
mftp.h file
Code:
#ifndef MFTP_H #define MFTP_H #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> #include <fcntl.h> #include <netinet/in.h> #include <netdb.h> #include <string.h> #define N 1024 #define NB_CMDS 11 #define OPEN 0 #define CD 1 #define MKD 2 #define RMD 3 #define QUIT 4 #define DIR 5 #define GET 6 #define PUT 7 #define PWD 8 #define DEL 9 #define HELP 10 const char *PROMPT="mftp> "; void prompt(void); void myconnect(char *,char *,char *); void pwd(void); void cd(char *); void quit(void); void mkd(char *); void rmd(char *); void dir(void); void get(char *); void put(char *); void del(char *); void aide(void); #endif
Code:
#include "mftp.h"
static char *commandes[NB_CMDS] = {
"open", "cd", "mkd", "rmd", "quit", "dir", "get", "put", "pwd", "del", "help"
};
int sd = 0;
int connecte = 0;
int main(int argc, char *argv[]){
char buff[N], *param; //1024
int j = 0, nb;
if( argc != 4){
printf("Usage: %s <server host> <user name> <password>\n", argv[0]);
exit(1);
}
printf("Pour voir le menu avec les commandes reconnues tappez 'help' :\n");
do{
memset(buff, '\0', N);
prompt();
gets(buff);
param = strchr(buff,' '); // param <- commande
if (param) {
*param=0;
param++;
}
for(j = 0; j < NB_CMDS; j++)
if( !strcmp(buff, commandes[j]))
break;
switch(j){
case(OPEN): if(connecte) printf("Deja connecte\n");
else myconnect(argv[1], argv[2], argv[3]);
break;
case(PWD): if(!connecte) printf("Non connecte!\n");
else pwd();
break;
case(CD): if(!connecte) printf("Non connecte!\n");
else cd(param);
break;
case(MKD): if(!connecte) printf("Non connecte!\n");
else mkd(param);
break;
case(RMD): if(!connecte) printf("Non connecte!\n");
else rmd(param);
break;
case(QUIT): quit();
return(0);
break;
case(DIR): if(!connecte) printf("Non connecte!\n");
else dir();
break;
case(GET): if(!connecte) printf("Non connecte!\n");
else get(param);
break;
case(PUT): if(!connecte) printf("Non connecte!\n");
else put(param);
break;
case(DEL): if(!connecte) printf("Non connecte!\n");
else del(param);
break;
case (HELP): aide();
break;
default: printf("%s commande inconnue\n", buff);
break;
}
}
while(1);
return(0);
}
void myconnect(char *host_serv, char *user_name, char *password){
struct sockaddr_in to;
struct hostent *host;
int tolen, len;
char buff[N];
char user[N];
char pass[N];
char *cwd = "CWD /\n";
to.sin_family = AF_INET;
to.sin_port = htons(2100);
host = gethostbyname(host_serv);
memcpy(&(to.sin_addr), host->h_addr, sizeof(to.sin_addr));
tolen = sizeof(to);
sd = socket(AF_INET, SOCK_STREAM, 0); // socket pour le controle de la connexion
if( 0 > connect(sd, (struct sockaddr *)&to, tolen)){
perror("connect");
exit(1);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("%s\n",buff);
//USER
strcat(user, "USER ");
strcat(user, user_name);
strcat(user, "\n");
strcat(pass, "PASS ");
strcat(pass, password);
strcat(pass, "\n");
if( send(sd, user, (strlen(user)+1), 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("%s\n",buff);
//PASS
if( send(sd, pass, (strlen(user)+1), 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("%s\n",buff);
//CWD
if( send(sd, cwd, strlen(cwd)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("%s\n",buff);
connecte = 1;
}
void pwd(){
char buff[N];
char *pwd = "PWD \n";
if( send(sd, pwd, strlen(pwd)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("vous etes dans '%s'\n",buff);
}
void cd(char *rep){
char cwd[N];
char buff[N];
memset(cwd, '\0', N);
strcat(cwd, "CWD ");
strcat(cwd, rep);
strcat(cwd, "\n");
if( send(sd, cwd, strlen(cwd)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("cd %s\n",buff);
}
void quit(){
char quit[N];
memset(quit, '\0', N*sizeof(char));
strcat(quit,"QUIT\n");
if(connecte)
if( send(sd, quit, strlen(quit)+1, 0) < 0 ){
perror("send");
exit(2);
}
close(sd);
sd=0;
printf("Au revoir \n");
}
void mkd(char *rep){
char mkd[N];
char buff[N];
memset(mkd, '\0', N*sizeof(char));
strcat(mkd,"MKD ");
strcat(mkd, rep);
strcat(mkd,"\n");
if( send(sd, mkd, strlen(mkd)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("%s\n",buff);
}
void rmd(char *rep){
char rmd[N];
char buff[N];
memset(rmd, '\0', N*sizeof(char));
strcat(rmd,"RMD ");
strcat(rmd, rep);
strcat(rmd,"\n");
if( send(sd, rmd, strlen(rmd)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("%s\n",buff);
}
void dir(){
char port[N];
char list[N];
char buff[N];
int min_port = 1025;
int max_port = 65535;
struct sockaddr_in serv_addr, cl_addr;
int sd_client, sd_server, len, i;
struct hostent *host;
memset(list, '\0', N*sizeof(char));
strcat(list,"LIST\n");
//le client devient server pour le serveur FTP
if( 0 > (sd_server = socket(AF_INET, SOCK_STREAM, 0) )){
perror("socket");
exit(1);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(serv_addr.sin_zero), '\0', 8);
len = sizeof(cl_addr);
for( i = min_port; i <= max_port; i++){
serv_addr.sin_port = htons(i);
if(0 <= bind(sd_server, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) )
break;
}
memset(buff, '\0', N*sizeof(char));
memset(port, '\0', N*sizeof(char));
sprintf(buff, "%d", serv_addr.sin_port);
printf("DIR %s %d\n", buff, htons(serv_addr.sin_port));
strcat(port,"PORT ");
strcat(port, buff);
strcat(port,"\n");
//PORT
if( send(sd, port, strlen(port)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("port %s\n",buff);
//LIST
if( send(sd, list, strlen(list)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("list %s\n",buff);
if( 0 > listen(sd_server, 5) ){ //da se postavi na 1
perror("listen");
exit(1);
}
if( 0> (sd_client = accept(sd_server, (struct sockaddr *)&cl_addr, &len) )){
perror("accept");
exit(1);
}
memset(buff, '\0', N*sizeof(char));
while( recv(sd_client, buff, N*sizeof(char), 0 ) > 0){
printf("%s\n",buff);
}
close(sd_server);
close(sd_client);
sd_server=0;
sd_client=0;
}
void get(char *file){
char port[N];
char retr[N];
char buff[N];
int min_port = 1025;
int max_port = 65535;
struct sockaddr_in serv_addr, cl_addr;
int sd_client, sd_server, len, nb0=1, nb1=1, fd, i;
struct hostent *host;
memset(retr, '\0', N*sizeof(char));
strcat(retr,"RETR ");
strcat(retr, file);
strcat(retr,"\n");
if( 0 > (sd_server = socket(AF_INET, SOCK_STREAM, 0))){
perror("socket");
exit(1);
}
//le client devient server pour le serveur FTP
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(serv_addr.sin_zero), '\0', 8);
len = sizeof(cl_addr);
for( i = min_port; i <= max_port; i++){
serv_addr.sin_port = htons(i);
if(0 <= bind(sd_server, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) )
break;
}
memset(buff, '\0', N*sizeof(char));
memset(port, '\0', N*sizeof(char));
sprintf(buff, "%d", serv_addr.sin_port);
printf("GET %s %d\n", buff, htons(serv_addr.sin_port));
strcat(port,"PORT ");
strcat(port, buff);
strcat(port,"\n");
//PORT
if( send(sd, port, strlen(port)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("port %s\n",buff);
if(0 > (fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR))) { //read/write
perror("open");
exit(1);
}
//RETR
if( send(sd, retr, strlen(retr)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("retr %s\n",buff);
if( 0 > listen(sd_server, 5) ){ //da se postavi na 1
perror("listen");
exit(1);
}
if( 0 > (sd_client = accept(sd_server, (struct sockaddr *)&cl_addr, &len))){
perror("accept");
exit(1);
}
memset(buff, '\0', N*sizeof(char));
while( nb0 != 0 ){
nb1 = recv(sd_client, buff, sizeof(buff), 0 ); //sizeof() + 1
nb0 = write(fd, buff, nb1);
if( nb0 == 0 ){
printf("Fichier recu\n");
nb0 = 0;
}
}
close(sd_server);
close(sd_client);
sd_server=0;
sd_client=0;
}
void put(char *file){
char port[N];
char stor[N];
char buff[N];
int min_port = 1025;
int max_port = 65535;
struct sockaddr_in serv_addr, cl_addr;
int sd_client, sd_server, len, nb, fd, i;
struct hostent *host;
memset(stor, '\0', N*sizeof(char));
strcat(stor,"STOR ");
strcat(stor, file);
strcat(stor,"\n");
if( 0 > (sd_server = socket(AF_INET, SOCK_STREAM, 0))){
perror("socket");
exit(1);
}
// le client devient server pour le serveur FTP
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(serv_addr.sin_zero), '\0', 8);
len = sizeof(cl_addr);
for( i = min_port; i <= max_port; i++){
serv_addr.sin_port = htons(i);
if(0 <= bind(sd_server, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) )
break;
}
memset(buff, '\0', N*sizeof(char));
memset(port, '\0', N*sizeof(char));
sprintf(buff, "%d", serv_addr.sin_port);
printf("PUT %s %d\n", buff, ntohs(serv_addr.sin_port));
strcat(port,"PORT ");
strcat(port, buff);
strcat(port,"\n");
//PORT
if( send(sd, port, strlen(port)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("port %s\n",buff);
if( 0 > (fd = open(file, O_RDONLY)) ){
perror("open");
exit(1);
}
printf("sled OPEN\n");
printf("On va envoye %s sur %d\n", stor, sd);
//STOR
if( send(sd, stor, strlen(stor)+1, 0) < 0 ){
perror("send");
exit(2);
}
/*memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("stor %s\n",buff);*/
if( 0 > listen(sd_server, 5) ){
perror("listen");
exit(1);
}
if( 0 > (sd_client = accept(sd_server, (struct sockaddr *)&cl_addr, &len) )){
perror("accept");
exit(1);
}
memset(buff, '\0', N*sizeof(char));
while( (nb = read(fd, buff, N)) > 0){
if( 0 > send(sd_client, buff, nb, 0) ){
perror("send");
exit(1);
}
}
close(sd_server);
close(sd_client);
sd_server=0;
sd_client=0;
close(fd);
}
void del(char *file){
char dele[N];
char buff[N];
memset(dele, '\0', N*sizeof(char));
strcat(dele,"DELE ");
strcat(dele, file);
strcat(dele,"\n");
if( send(sd, dele, strlen(dele)+1, 0) < 0 ){
perror("send");
exit(2);
}
memset(buff, '\0', N*sizeof(char));
if( recv(sd, buff, sizeof(buff), 0 ) < 0){
perror("recv");
exit(5);
}
else printf("%s\n",buff);
}
void prompt(void) {
printf("%s",PROMPT);
fflush(stdout);
}
void aide(void){
printf("Les commandes FTP sont les suivantes :\n");
printf("------------------------------------------------------------\n");
printf(" QUIT Quitte le ftp\n");
printf(" OPEN Connecte le client sur le serveur\n");
printf(" CD Changement du repertoire courant\n");
printf(" PWD Affiche le repertoire courant\n");
printf(" GET Telechargement d`un fichier\n");
printf(" PUT Envoie un fichier sur le serveur\n");
printf(" DEL Suppression d`un fichier\n");
printf(" MKD Creation d`un repertoire\n");
printf(" RMD Suppression d`un repertoire\n");
printf(" DIR Affiche la liste des fichier dans le repertoire courant\n");
printf(" HELP Liste des commandes reconnues par le client\n");
printf("------------------------------------------------------------\n");
}
server.h
Code:
/**
* Fichier: server.h
*
*/
#ifndef SERVER_H
#define SERVER_H
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#define BUFF_LEN 128
//longueure maximale d'une commande
#define CMD_LEN 1024
//Limite maximale du nombre des clients qui peuvent se connecter
#define MAX_USER_LIMIT 10
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
/**
* Structure: client
* Represente la structure utilisee par le serveur pour stocker de l'information
* necessaire a la communication avec le client
*/
typedef struct {
int sock,pid; //socket de communication; pid du processus fils servant le client
struct in_addr addrip; //adresse IP du client .s_addr
unsigned short int dataport; //port pour la connexion servant du transfert des donnees (fichiers, liste des fichiers dans un rep)
char curdir[256]; //repertoire dans la quelle se trouve le cliet
} client_t, *client;
extern client clients[]; //tableau des clients
extern int nb_users; //utilisatuers actuellement connectes
extern stop; //variable a tester : utilisee pour arreter le serveur
/* prototypes des fonctions */
void init_conn(void); //accept; procedure qui accepte/refuse un nouveau client
void waitchild(int); //attente d'un processus fils
void main_loop(void); //boucle principale
void exec_comm(int i); //execute une commande en provenance du client: mkd, rmd, list, etc.
#endif
Code:
/**
* Fichier: server.c
*
*/
#include "server.h"
client clients[MAX_USER_LIMIT];
int stop = 0;
int sd_server=0; //socket d'ecoute sur le serveur
const int maxusers= MAX_USER_LIMIT; // max utilisatuers connectes
int nb_users=0; //utilisatuers actuellement connectes
int max_user_sock = 0; //socket de valeur maximale
int serverport = 2100; //port d'ecoute du serveur
char *prompt_symb = "serv>"; //invite de commande pour l'administration du serveur
/**
* Procedure: prompt
* Affiche l'invite de commande "serv>"
*/
void prompt(void) {
printf("%s",prompt_symb);
fflush(stdout);
}
/**
* Procedure: init_conn
* procedure qui accepte/refuse un nouveau client
*/
void init_conn(void){
int i, sd_client, len;
char buff[BUFF_LEN];
struct sockaddr_in cl_addr;
struct hostent *host;
len = sizeof(cl_addr);
if( 0 > (sd_client = accept(sd_server, (struct sockaddr *)&cl_addr, &len)) ){
perror("accept");
return;
}
//test si le nombre maximale de clients connectes est atteint
if(nb_users == maxusers){
//le nombre max d'utilisatuers connectes est atteint !!!
printf("\nLe nombre max d'utilisatuers connectes est atteint !!!\n");
memset(buff, '\0', BUFF_LEN);
sprintf(buff, "Le serveur est occupe.\r\n");
send(sd_client, buff, strlen(buff), 0);
close(sd_client);
return;
}
else{ //on accepte la connexion et on remplit la structure du client
clients[nb_users]->addrip.s_addr = cl_addr.sin_addr.s_addr; // on doit copier l'adresse IP du client dans la structure
clients[nb_users]->sock = sd_client;
strcpy(clients[nb_users]->curdir,"/");
clients[nb_users]->pid = 0;
clients[nb_users]->dataport = 0;
printf("\nUn nouveau client s'est connecte \n");
max_user_sock = MAX(max_user_sock, clients[nb_users]->sock);
nb_users++;
printf("Nombre des clients connectes: %d\n", nb_users);
prompt();
}
memset(buff, '\0', BUFF_LEN);
sprintf(buff, "Bienvenu\r\n");
send(sd_client, buff, strlen(buff), 0);
}
/**
* Procedure: waitchild
* attente d'un processus fils
*/
void waitchild(int n) {
while (wait3(NULL, WNOHANG, NULL) > 0);
}
/**
* Procedure: main_loop
* boucle principale du serveur: bind, listen, select
*/
void main_loop(void)
{
int i,n,addr;
unsigned int sock_size;
fd_set readfds, testfds;
char cmd[CMD_LEN];
struct sockaddr_in sa;
signal(SIGPIPE,SIG_IGN);
signal(SIGCHLD,waitchild);
/* server init */
printf("Demarrage du serveur ... \n");
if ((sd_server=socket(AF_INET,SOCK_STREAM,0)) < 0) {
perror("socket");
exit(1);
}
sock_size=sizeof(struct sockaddr_in);
memset(&sa,0,sock_size);
sa.sin_family=AF_INET;
sa.sin_port=htons(serverport);
addr=INADDR_ANY;
memcpy(&sa.sin_addr.s_addr,&addr,sizeof(int));
if (bind(sd_server,(struct sockaddr *)&sa,sock_size)<0) {
perror("bind");
exit(1);
}
if (listen(sd_server,5)<0) {
perror("listen");
exit(1);
}
printf("OK\n\n");
prompt();
FD_ZERO(&readfds);
FD_SET(1,&readfds);
FD_SET(sd_server,&readfds);
stop = 0;
while (!stop) {
testfds = readfds;
for (i = 0; i < nb_users; i++)
if (clients[i]->sock)
FD_SET(clients[i]->sock,&testfds);
//selectoin d'un descripteur actif
if( 0 > (n = select(max_user_sock, &testfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0))){
if (errno!=EINTR || n != -1)
exit(1);
}
//qqch a lire a partir du clavier (commande d'administration)
if(FD_ISSET(1,&testfds)) {
i=read(1,cmd,sizeof(cmd));
cmd[i-1]=0;
serv_comm(cmd);
if (stop) break; //on sort du while et on arrete le serveur
prompt();
}
if (FD_ISSET(sd_server,&testfds)) init_conn(); // nouveau client
//lire des informations provenant des clients
for (i = 0; i < nb_users; i++) {
if (clients[i]->sock) {
if (FD_ISSET(clients[i]->sock,&testfds))
exec_comm(i); //i - numero du client dans le tableau des clients
prompt();
}
}
}
close(sd_server);
printf("Serveur arrete.\n");
}
/**
* Fonction: main
*/
int main(int argc, char *argv[]){
int i;
for (i = 0; i < maxusers; i++) {
clients[i]=(client_t *)malloc(sizeof(client_t));
clients[i]->sock=0;
}
main_loop();
for(i = 0; i < maxusers; i++) {
if (clients[i]) {
free(clients[i]);
clients[i]=(client_t *)NULL;
}
}
return(0);
}
Code:
/** * Fichier: serv_comm.h * */ #ifndef SERV_COMM #define SERV_COMM #include "server.h" void serv_comm(char *); //execute une commande d'administration void help(void); //affiche un menu d'aide void quit(void); //arrete le serveur #endif
Code:
/**
* Fichier: serv_comm.c
*
*/
#include "serv_comm.h"
int stop;
/* Execute les commandes d'administration du serveur */
void serv_comm(char *cmd){
/* Plus tard, si l'on disposera avec plus de commandes, a utiliser plustot un switch */
if(strcmp("quit", cmd) == 0) quit();
else
if(strcmp("help", cmd) == 0) help();
else printf("Commande %s inconnue\n", cmd);
}
/* Affiche les commandes d'administration disponibles sur le serveur */
void help(void) {
char *help_info = "Affiche les commandes disponibles";
char *quit_info = "Quitte le serveur";
printf("\nCommandes:\n");
printf("%s - %s\n","help", help_info);
printf("%s - %s\n","quit", quit_info);
printf("\n");
}
/* Commande qui arrete le serveur. Pour rendre compatible avec rfc FTP, if faut aussi envoyer un msg commme quoi le serv s'arrete */
void quit(void)
{
int i;
for (i = 0; i < nb_users; i++) {
if (clients[i]->sock)
close(clients[i]->sock);
}
stop=1;
}
Code:
/** * Fichier: exec_comm.h * */ #ifndef EXEC_COMM_H #define EXEC_COMM_H #include "server.h" #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <unistd.h> #include <dirent.h> /** * Commandes du protocole * */ // Le client quitte le serveur #define QUIT 0 //Le client envoie son port de donnees #define PORT 1 //Le client veut la liste des fichiers dans le rep. courant #define LIST 2 //Le client veut changer le repertoire courant #define CWD 3 //Le client veut savoir dans quel rep. il est actuellemet #define PWD 4 //Le client veut telecharger un fichier #define RETR 5 //Le client envoie son user name #define USER 6 //Le client envoie son password #define PASS 7 //Le client veut envoyer un fichier sur le serveur #define STOR 8 //Le client veut remonter dans le rep. precedent #define CDUP 9 //Le client veut effacer un fichier #define DELE 10 //Le client veut creer un rep. #define MKD 11 //Le client veux supprimer un client #define RMD 12 /* Prototypes des fonctions */ void exec_comm(int); //execute une commande void my_list(int); //donne la liste des fichiers d'un repertoire void stor(int,char *); //recupere un fichier a partir du client void retr(int,char *); //envoie un fichier vers le clients int mkd(int,char *); //cree un repertoire int rmd(int,char *); //supprime un repertoire vide void dele(int,char *); //supprime un fichier #endif
Code:
/**
* Fichier: exec_comm.c
*
*/
#include "exec_comm.h"
//tableau qui contient les commandes du protocole
const char *commandes[13] = {
"QUIT", "PORT", "LIST", "CWD", "PWD", "RETR", "USER", "PASS", "STOR", "CDUP", "DELE", "MKD", "RMD"
};
int nb_users;
const char *ok = "OK\r\n";
/**
* Procedure: exec_comm
* execute une commande
*/
void exec_comm(int cl){
int size,j, port;
char buff[1024], *param;
fd_set fds;
memset(buff, '\0', 1024);
size = recv(clients[cl]->sock, buff, sizeof(buff), 0);
printf("recu: %s\n", buff);
//pour recuperer la commande et son parametre
buff[size-2]=0; // -'\r' et -'\n'
param = strchr(buff,' '); // param <- commande
if (param) {
*param=0;
param++;
}
for (j = 0; j < strlen(buff); j++)
buff[j]=toupper(buff[j]);
for (j = 0; j < 13; j++)
if (!strcmp(buff,commandes[j])) break;
//on teste successivment quelle commande le serveur a recu et apres il execute la fonction appropriee: list, cwd, pwd, etc.
switch(j){
case QUIT: if (clients[cl]->pid) kill(clients[cl]->pid,SIGTERM);
clients[cl]->pid=0;
close(clients[cl]->sock);
clients[cl]->sock=0; //NIKOGA AMA NIKOGA NE GO KOMENTIRAI !!!!!!!!!
clients[cl]->dataport=0;
nb_users--;
printf("%s\n", commandes[j]);
break;
case PORT: port = atoi(param);
clients[cl]->dataport = port;
printf("%s %s\n", commandes[j], param);
send(clients[cl]->sock, ok, strlen(ok)+1, 0);
break;
case CWD: memset(clients[cl]->curdir, '\0', (strlen(clients[cl]->curdir)+1));
strcpy(clients[cl]->curdir,param); //on passe le chemin absolu !!!
send(clients[cl]->sock, ok, strlen(ok)+1, 0);
printf("%s %s\n", commandes[j],clients[cl]->curdir);
break;
case PWD: send(clients[cl]->sock, clients[cl]->curdir, strlen(clients[cl]->curdir)+1, 0);
printf("%s %s\n",commandes[j], clients[cl]->curdir);
break;
case USER: send(clients[cl]->sock, ok, strlen(ok)+1, 0);
printf("%s %s\n", commandes[j], param);
break;
case PASS: send(clients[cl]->sock, ok, strlen(ok)+1, 0);
printf("%s %s\n", commandes[j], param);
break;
// Vu que la liste des fichiers peut etre une taille considerable, il vaut mieux creer un fils
// qui s'occupera avec le client
case LIST: if( (clients[cl]->pid = fork()) == 0 ){
send(clients[cl]->sock, ok, strlen(ok)+1, 0);
my_list(cl);
}
//send(clients[cl]->sock, ok, strlen(ok)+1, 0);
printf("%s %s\n", commandes[j], clients[cl]->curdir);
break;
//Vu qu'un fichier peut etre d'une grande taille, il vaut mieux creer un fils
// qui s'occupera avec l'envoi vers le client
case RETR: if( (clients[cl]->pid = fork()) == 0 ) {
send(clients[cl]->sock, ok, strlen(ok)+1, 0);
retr(cl, param);
}
printf("%s %s\n", commandes[j], param);
break;
//Vu qu'un fichier peut etre d'une grande taille, il vaut mieux creer un fils
// qui s'occupera avec la recuperation a partir du client
case STOR: if( (clients[cl]->pid = fork()) == 0 ){
//send(clients[cl]->sock, ok, strlen(ok)+1, 0);
stor(cl, param);
}
printf("%s %s\n", commandes[j], param);
break;
//Vu qu'un fichier peut etre d'une grande taille, il vaut mieux creer un fils
// qui s'occupera avec la suppression
case DELE: if( (clients[cl]->pid = fork()) == 0 ) dele(cl,param);
send(clients[cl]->sock, ok, strlen(ok)+1, 0);
printf("%s %s\n", commandes[j], param);
break;
case MKD: mkd(cl,param);
send(clients[cl]->sock, ok, strlen(ok)+1, 0);
printf("%s %s\n", commandes[j], param);
break;
case RMD: rmd(cl,param);
send(clients[cl]->sock, ok, strlen(ok)+1, 0);
printf("%s %s\n", commandes[j], param);
break;
//Par defaut, on considere que si un client envoie des commandes incomprehensibles, il doit etre deconnecte
default: if (clients[cl]->pid) kill(clients[cl]->pid,SIGTERM);
if (clients[cl]->pid) kill(clients[cl]->pid,SIGTERM);
clients[cl]->pid=0;
close(clients[cl]->sock);
clients[cl]->sock = 0;
clients[cl]->dataport = 0;
nb_users--;
printf("Client %d deconnexion brutale\n",cl);
break;
}
}
/**
* Procedure: my_list
* envoie la liste des fichiers situes dans un repertoire au client
*/
void my_list(int cl){
struct dirent *dirp;
DIR *dirfd;
int sd, tolen, nb;
struct sockaddr_in to;
struct hostent *host;
to.sin_family = AF_INET;
to.sin_port = clients[cl]->dataport;
to.sin_addr.s_addr = clients[cl]->addrip.s_addr; //IP
tolen = sizeof(to);
if( (sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
perror("socket");
exit(1);
}
//le serveur se connecte vers le client
if(0 > connect(sd, (struct sockaddr*)&to, tolen)){
perror("connect MY_LIST");
exit(1);
}
//le serveur ouvre le reprtoire desire par le client
if( !(dirfd = opendir(clients[cl]->curdir))){
perror("opendir");
exit(1);
}
//le serveur envoie ce qu'il a lu a partir du repertoire vers le client
while( (dirp = readdir(dirfd)) != NULL) {
send(sd, dirp->d_name, 1024*sizeof(char), 0);
}
closedir(dirfd);
close(sd);
exit(0);
}
/**
* Procedure: stor
*
* Recupere un fichier a partir du client. En fait le client veux envoyer un fichier sur le serveur.
* Pour faire cela, il envoye premieremt un port (port des donnees) sur lequel il se met en attente d'une connexion
* de la part du serveur.
* De la cote du serveur, lorsqu'on a recu le port des donnees, on essaye d'etablire une connexion avec le client.
* Une fois la connexion etablie, le serveur est pret de recevoir des donnees provenant du client.
* Le fichier sera recu dans le repertoire courant du client (cote serveur)
*/
void stor(int cl, char *filename){
int fd, nb0=1, nb1=1;
char buff[1024];
char fichier[1024]; //contient le chemin absolut
int s, tolen, nb;
struct sockaddr_in to;
struct hostent *host;
memset(fichier, '\0', 1024*sizeof(char));
strcat(fichier, clients[cl]->curdir);
strcat(fichier,"/");
strcat(fichier, filename);
printf("stor FILE: %s\n", fichier);
//fd = open(fichier, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR); //read/write
to.sin_family = AF_INET;
to.sin_port = clients[cl]->dataport;
to.sin_addr.s_addr = clients[cl]->addrip.s_addr; //IP
tolen = sizeof(to);
if( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0){
perror("socket");
exit(1);
}
if(0 > connect(s, (struct sockaddr*)&to, tolen)){
perror("connect STOR");
exit(1);
}
fd = open(fichier, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR); //read/write
memset(buff, '\0', 1024*sizeof(char));
while( nb0 != 0 ){
nb1 = recv(s, buff, sizeof(buff), 0 ); //strlen + 1
nb0 = write(fd, buff, nb1);
if( nb0 == 0 ){
printf("Fichier recu\n");
nb0 = 0;
}
}
close(s);
close(fd);
s = 0;
exit(1);
}
/**
* Procedure: retr
*
* Recupere un fichier a partir du serveur. En fait le client veux telecharger un fichier a partir du serveur.
* Pour faire cela, il envoye premieremt un port (port des donnees) sur lequel il se met en attente d'une connexion
* de la part du serveur.
* De la cote du serveur, lorsqu'on a recu le port des donnees, on essaye d'etablire une connexion avec le client.
* Une fois la connexion etablie, le serveur est pret d'envoyer des donnees vers client.
* Le fichier sera recu dans le repertoire ou le client a ete demarre.
*/
void retr(int cl, char *filename){
int fd, nb0, nb1;
char buff[1024];
char fichier[1024];
int sd, tolen, nb;
struct sockaddr_in to;
struct hostent *host;
memset(fichier, '\0', 1024*sizeof(char));
strcat(fichier, clients[cl]->curdir);
strcat(fichier,"/");
strcat(fichier, filename);
printf("retr FILE: %s\n", fichier);
if( (fd = open(fichier, O_RDONLY)) == -1 ){ //read
perror("open");
exit(1);
}
to.sin_family = AF_INET;
to.sin_port = clients[cl]->dataport;
to.sin_addr.s_addr = clients[cl]->addrip.s_addr; //IP
tolen = sizeof(to);
if( (sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
perror("socket");
exit(1);
}
if(0 > connect(sd, (struct sockaddr*)&to, tolen)){
perror("connect");
exit(1);
}
while( (nb = read(fd, buff, 1024)) > 0 ){
//printf("sent %d\n", nb);
send(sd, buff, nb, 0);
printf("sent %d\n", nb);
}
close(sd);
sd=0;
exit(0);
}
/**
* Procedure: mkd
*
* Creation d'un repertoire sur le serveur, dans le repertoire courant du client (cote serveur)
*/
int mkd(int cl, char *dir_name){
char rep[1024];
memset(rep, '\0', 1024*sizeof(char));
strcat(rep, clients[cl]->curdir);
strcat(rep,"/");
strcat(rep, dir_name);
if( mkdir(rep, 0755) == -1 ){
perror("mkdir");
return(0);
}
printf("Repertoire %s cree\n", rep);
return(1);
}
/**
* Procedure: rmd
*
* Suppression d'un repertoire VIDE sur le serveur, dans le repertoire courant du client (cote serveur)
*/
int rmd(int cl, char *dir_name){
char rep[1024];
memset(rep, '\0', 1024*sizeof(char));
strcat(rep, clients[cl]->curdir);
strcat(rep,"/");
strcat(rep, dir_name);
if( rmdir(rep) == -1 ){
perror("rmdir");
return(0);
}
printf("Repertoire %s supprime\n", rep);
return(1);
}
/**
* Procedure: dele
*
* Suppression d'un fichier sur le serveur, dans le repertoire courant du client (cote serveur)
*/
void dele(int cl, char *filename){
char fichier[1024];
memset(fichier, '\0', 1024*sizeof(char));
strcat(fichier, clients[cl]->curdir);
strcat(fichier,"/");
strcat(fichier, filename);
if( unlink(fichier) == -1 ){
perror("unlink");
exit(1);
}
printf("Fichier %s supprime\n", fichier);
exit(1);
}

