根据RFC 959实现的一个简易版本,用户名和密码都只是写在代码中,也只提供了PORT模式而没有PASV模式。实现了基本的登录,上传下载以及目录的变更(用leapftp,浏览器的ftp://均测试过),后续会继续写一些其他功能,尽量做成一个像样的ftpserver,但新日志只贴新函数就好,不想把一个日志搞太大。


#include "unpheader.h"
char *env_init[] ={"LC_ALL=en_US",NULL};

struct ftpuser{
 char dataip[20];
 int dataport;
 int loginok;
 int userok;
};

static int listenport=8021;
void init_ftpuser(struct ftpuser *myftp)
{
 memset(myftp->dataip,'�',20);
 myftp->dataport = 0;
 myftp->loginok = 0;
 myftp->userok = 0;
}

void do_stor(int connfd,char *storfile,struct ftpuser *myftp)
{
 char *storstart = "150 Opening data connection.rn";
 char *storend = "226 Transfer completed.rn";
 umask(S_IWGRP | S_IWOTH);
 int filefd = open(storfile,O_RDWR | O_CREAT,RWRWRW);
 write(connfd,storstart,strlen(storstart));
 int datasockfd = getconnection(myftp->dataip,myftp->dataport);
 char buf[MAXLINE];
 int n=0;
 while((n = read(datasockfd,buf,MAXLINE)) > 0)
 {
   buf[n]='�';
   write(filefd,buf,n);
 }
 close(datasockfd);
 write(connfd,storend,strlen(storend));
 return;
}

void do_retr(int connfd,char *retrfile,struct ftpuser *myftp)
{
 char *retrstart = "150 Opening data connection.rn";
 char *retrend = "226 Transfer completed.rn";
 char *retrnofile = "503 no such file.rn"; 
 int filefd;
 if( (filefd = open(retrfile,O_RDONLY) ) != -1)
 {
  write(connfd,retrstart,strlen(retrstart));
  int datasockfd = getconnection(myftp->dataip,myftp->dataport);
  char buf[MAXLINE];
  int n=0;
  while((n = read(filefd,buf,MAXLINE)) > 0)
  {
   buf[n]='�';
   write(datasockfd,buf,n);
  }
  close(datasockfd);
  write(connfd,retrend,strlen(retrend));
 }
 else
  write(connfd,retrnofile,strlen(retrnofile));
 return;
}

void do_mode(int connfd,char *modetype)
{
 char *modeok = "200 stream mode is okrn";
 char *modefail = "500 only stream mode is supportrn";
 if(strncmp(modetype,"S",1) == 0)
  write(connfd,modeok,strlen(modeok));
 else
  write(connfd,modefail,strlen(modefail));
 return;
}

void do_type(int connfd,char *type)
{
 char *settypeI = "200 type set to I.rn";
 char *settypeA = "200 type set to A.rn";
 char *seterror = "500 parm error.rn";
 if(strncasecmp(type,"I",1) == 0)
  write(connfd,settypeI,strlen(settypeI));
 else if(strncasecmp(type,"A",1) == 0)
  write(connfd,settypeA,strlen(settypeA));
 else
  write(connfd,seterror,strlen(seterror));
 return ;
}

void do_pwd(int connfd,struct ftpuser *myftp)
{
 char output[MAXLINE];
 memset(output,'�',MAXLINE);
 char currdir[MAXLINE];
 memset(currdir,'�',MAXLINE);
 getcwd(currdir,MAXLINE);
 snprintf(output,MAXLINE,"257 "%s"rn",currdir);
 write(connfd,output,strlen(output));
 return;
}

void do_noop(int connfd)
{
 write(connfd,"200 NOOP ok.rn",14);
 return;
}

void do_cwd(int connfd,char *postfix,char *rootdir)
{
 char *cwdok = "250 Directory successfully changed.rn";
 char *cwderror = "500 Fail to change directory.rn";
 char currdir[MAXLINE];
 memset(currdir,'�',MAXLINE);
 getcwd(currdir,MAXLINE);
 if( strcmp(rootdir,currdir) == 0 && strcmp(postfix,"..") == 0)
  write(connfd,cwderror,strlen(cwderror));
 else if(chdir(postfix) >= 0)
  write(connfd,cwdok,strlen(cwdok));
 else
  write(connfd,cwderror,strlen(cwderror));
 return ;
}

void do_quit(int connfd)
{
 char *quitok="221 Goodbye.rn";
 write(connfd,quitok,strlen(quitok));
 return ;
}

void do_user(int connfd,char *username,struct ftpuser* myftp)
{
 char *nameok="331 please specify the passwordrn";
 char *nameerror = "430 username errorrn";
 char buf[MAXLINE];
 if(strncmp(username,"yourname",6) == 0)
 {
  write(connfd,nameok,strlen(nameok));
  myftp->userok = 1;
 }
 else
  write(connfd,nameerror,strlen(nameerror));
 return;
}

void do_pass(int connfd,char *userpass,struct ftpuser* myftp)
{
 char *passerror = "430 password errorrn";
 char *loginok = "230 Login Successfulrn";
 char *nouser = "530 No User Specifiedrn";
 if(strncmp(userpass,"yourpass",8) == 0)
 {
  if(myftp->userok == 1)
  {
   write(connfd,loginok,strlen(loginok));
   myftp->loginok = 1;
  }
  else
   write(connfd,nouser,strlen(nouser));
 }
 else
  write(connfd,passerror,strlen(passerror));
 return;
}

void do_pasv(int connfd)
{
 char *notsupport="500 passive mode not supported.rn";
 write(connfd,notsupport,strlen(notsupport));
 return;
}

void do_list(int connfd,struct ftpuser* myftp)
{
 char *noport = "425 User Port Firstrn";
 char *opening = "150 Here comes the directory listing.rn";
 char *transferok = "226 Transfer complete.rn";
 if( myftp->dataport != 0)
 {
  write(connfd,opening,strlen(opening));
  pid_t pid;
  if((pid = fork()) == 0)
  {
   close(connfd);
   int datasockfd = getconnection(myftp->dataip,myftp->dataport); 
   dup2(datasockfd,1);
   close(datasockfd);
   execle("/bin/ls","ls","-lan","--time-style=+%b %d %H:%M",(char *)0,env_init);
  }
  else
  {
   waitpid(pid,NULL,0);
   write(connfd,transferok,strlen(transferok));  
  }
 }
 else
 {
  write(connfd,noport,strlen(noport));
 }
}

void do_port(int connfd,char *ipport,struct ftpuser* myftp)
{
 char *portok="200 PORT Command successful.rn";
 char temp[MAXLINE];
 strncpy(temp,ipport,strlen(ipport));
 memset(myftp->dataip,'�',20);
 strcat(myftp->dataip,strtok(temp,","));
 int i=0;
 while(i<3)
 {
  strcat(myftp->dataip,".");
  strcat(myftp->dataip,strtok(NULL,","));
  i++;
 }
 myftp->dataport = atoi(strtok(NULL,",")) * 256 ;
 myftp->dataport = myftp->dataport + atoi(strtok(NULL,","));
 write(connfd,portok,strlen(portok));
 return;
}

void handler(int connfd,char* filedir)
{
 int n;
 char command[MAXLINE];
 char rootdir[MAXLINE];
 memset(rootdir,'�',MAXLINE);
 getcwd(rootdir,MAXLINE);
 struct ftpuser myftp;
 init_ftpuser(&myftp);
 char *welcome="220 welcome to myFTP!rn";
 write(connfd,welcome,strlen(welcome));
 while(( n = read(connfd,command,MAXLINE))>0)
 {
  errno = 0;
  if( command[n-2] == 'r')
   command[n-2] = '�';
  if( command[n-1]== 'n')
   command[n-1] = '�';
  printf("get command: %sn",command);
  if( strncmp(command,"USER ",5) == 0)
   do_user(connfd,command + 5,&myftp);
  else if( strncmp(command,"PASS ",5) == 0)
   do_pass(connfd,command + 5,&myftp);
  else if(strncmp(command,"LIST",4) == 0) //list file
   do_list(connfd,&myftp);
  else if(strncmp(command,"CWD ",4) == 0)  //change dir
   do_cwd(connfd,command + 4,rootdir);
  else if(strncmp(command,"PWD",3) == 0)
   do_pwd(connfd,&myftp);
  else if(strncmp(command,"PORT ",5) == 0)
   do_port(connfd,command + 5,&myftp);
  else if(strncmp(command,"PASV",4) == 0)
   do_pasv(connfd);
  else if(strncmp(command,"MODE ",5) == 0)
   do_mode(connfd,command + 5);
  else if(strncmp(command,"TYPE ",5) == 0)
   do_type(connfd,command + 5);
  else if(strncmp(command,"RETR ",5) == 0)
   do_retr(connfd,command + 5,&myftp);
  else if(strncmp(command,"STOR ",5) == 0)
   do_stor(connfd,command + 5,&myftp);
  else if(strncmp(command,"CDUP",4) == 0)  //CDUP
   do_cwd(connfd,"..",rootdir);
  else if(strncmp(command,"QUIT",4) == 0)
  {
   do_quit(connfd);
   break;
  }
  else
   write(connfd,"500 unknown command.rn",22);
 }
 close(connfd);
 return;
}

int main(int argc,char *argv[])
{
 int listenfd,connfd;
 struct sockaddr_in cliaddr;
 socklen_t clilen;
 pid_t handlerpid;
 listenfd = initlisten(listenport);
 chdir(argv[1]);
 printf("server has started,listen port is %dn",listenport);
 while(1)
 {
  if((connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&clilen)) == -1)
  {
   printf("accept error! %s",strerror(errno));
   return errno;
  }
  printf("get a connectionn");
  if((handlerpid = fork()) == 0)
  {
   handler(connfd,argv[1]);
   exit(0);
  }
  close(connfd);
 }
 return 0;
}
转载请注明来源:Leoncom-《Unix_Socket机制实现FTPServer》
Trackback

only 1 comment untill now

  1. A person primarily assist for making severely threads I might condition. Right here is the brand new My spouse and i went to your internet web site and now? I personally amazed while using the exploration you have made to produce this specific post amazing. Exceptional employment!

Add your comment now