📄 myftp_state_machine.c
字号:
strcpy(p_thesession->cur_file_name,p_thesession->p_cmd_line->arg);
return stor_file;
}
static unsigned long stor_num;//该变量是一个文件域变量,用于记录上载数据大小
/*=======================================================================
function:上载文件子进程所发送的信号的处理函数。当数据传输子进程结束时,进入该函数,对传输的数据量进程统计
remark:信号处理函数内部不能有不可重入函数出现,比如标准输入输出函数等
========================================================================*/
void myftp_stor_file_stat(int signo, siginfo_t *info, void *context)
{
stor_num+=info->si_value.sival_int;
}
/*=================================================================================
function:上载文件命令STOR函数
注:数据传输时,有PORT主动模式,PASV被动模式之分
=================================================================================*/
int myftp_cmd_handle_stor(pMYFTP_SESSION p_thesession)
{
if (*p_thesession->user_str=='\0'||*p_thesession->passwd_str==0)
{
write(p_thesession->cmd_cntl_fd,"530 Not logged in.\r\n", strlen("530 Not logged in.\r\n"));
return -1;
}
static unsigned int file_num;
int stor_file = myftp_creat_transfile(p_thesession);
struct sigaction sigact;
sigact.sa_flags=SA_SIGINFO;
sigact.sa_sigaction=myftp_stor_file_stat;
if (sigaction(SIGUSR1, &sigact, NULL)==-1)//安装信号捕获函数,数据传输子进程结束时,该函数收到信号,并转入有参数sigact指向的函数作相应的处理。
{
die("set sig handler error\n");
}
int trans_file_fd=fork();//创建子进程专用于数据传输
switch (trans_file_fd)
{
case -1:
return -1;
break;
case 0:
if (-1 == stor_file)
{
if (p_thesession->is_anonymous)
{
char* __pstr="550 Permission denied.\r\n";
write(p_thesession->cmd_cntl_fd, __pstr, strlen(__pstr));
}
else
{
write(p_thesession->cmd_cntl_fd, "553 Could not create file.\r\n", strlen("553 Could not create file.\r\n"));
}
exit(0);
}
write(p_thesession->cmd_cntl_fd, "150 OK to send data.\r\n", strlen("150 Ok to send data.\r\n"));
unsigned int read_count;
static unsigned int read_sum;
char data_buf[1024];
int tmp_data_fd=-1;
int len=0;
len= sizeof(data_buf);
lseek(stor_file, (long)p_thesession->transfile_start_pos, SEEK_SET);
memset(data_buf, 0, len);
if (p_thesession->is_port_or_pasv==PORT)
{
tmp_data_fd=p_thesession->port_data_fd;
}
else
{
MYFTP_SOCKADDR tmp_data_addr;
int len=sizeof(MYFTP_SOCKADDR);
p_thesession->pasv_data_fd=accept(p_thesession->pasv_listen_fd,&tmp_data_addr.un.u_sockaddr,&len);
if(p_thesession->pasv_data_fd==-1)
{
perror("STOR accept client_id");
}
close(p_thesession->pasv_listen_fd);
tmp_data_fd=p_thesession->pasv_data_fd;
}
unsigned long int i=0;
while (read_count=read(tmp_data_fd, data_buf, len))
{
i++;
if (!(i%myftp_conf.file_trans_rate))
usleep(50*10000+50*10000);//这个限速比较精确,浮动范围为-1%~+1%
int write_count=write(stor_file, data_buf, read_count);
read_sum+=read_count;
memset(data_buf, 0, len);
}
close(tmp_data_fd);
close(stor_file);
write(p_thesession->cmd_cntl_fd, "226 File receive OK.\r\n", strlen("226 File receive OK.\r\n"));
close(p_thesession->cmd_cntl_fd);
sigval_t val;
val.sival_int=read_sum;
if(sigqueue(getppid(),SIGUSR1,val)==-1)//利用发送信号函数sigqueue将统计的数据通过该函数的第3个参数传递给父进程,即传递给控制连接进程
{
die("upload sigqueue error\n");
}
exit(0);
default:
p_thesession->up_file_num=++file_num;
p_thesession->data_trans_child_pid=trans_file_fd;
close(stor_file);
close(p_thesession->pasv_data_fd);
close(p_thesession->port_data_fd);
return -1;
}
}
/*=================================================================================
function:续传文件命令APPE处理函数
=================================================================================*/
int myftp_cmd_handle_appe(pMYFTP_SESSION p_thesession)
{
if (*p_thesession->user_str=='\0'||*p_thesession->passwd_str==0)
{
write(p_thesession->cmd_cntl_fd,"530 Not logged in.\r\n", strlen("530 Not logged in.\r\n"));
return;
}
static unsigned int file_num;
struct sigaction sigact;
sigact.sa_flags=SA_SIGINFO;
sigact.sa_sigaction=myftp_stor_file_stat;//专用于统计传输数据量的函数
int stor_file = myftp_creat_transfile(p_thesession);
if (sigaction(SIGUSR1, &sigact, NULL)==-1)//安装信号捕获函数,数据传输子进程结束时,该函数收到信号,并转入有参数sigact指向的函数作相应的处理。
{
die("set sig handler error\n");
}
int trans_file_fd=fork();//产生子进程专用于数据传输
switch (trans_file_fd)
{
case -1:
return -1;
break;
case 0:
if (-1 == stor_file)
{
if (p_thesession->is_anonymous)
{
char* _tmp_="550 Permission denied.\r\n";
write(p_thesession->cmd_cntl_fd, _tmp_, strlen(_tmp_));
}
else
{
char* tmp="553 Could not create file.\r\n";
write(p_thesession->cmd_cntl_fd, tmp, strlen(tmp));
}
exit(0);
}
write(p_thesession->cmd_cntl_fd, "150 OK to send data.\r\n", strlen("150 Ok to send data.\r\n"));
unsigned int read_count;
static unsigned int read_sum;
char data_buf[1024];
int len=0;
int tmp_data_fd=-1;
len= sizeof(data_buf);
lseek(stor_file, 0, SEEK_END);
memset(data_buf, 0, len);
if (p_thesession->is_port_or_pasv==PORT)//PORT模式
{
tmp_data_fd=p_thesession->port_data_fd;
}
else//PASV模式
{
MYFTP_SOCKADDR tmp_data_addr;
int len=sizeof(MYFTP_SOCKADDR);
p_thesession->pasv_data_fd=accept(p_thesession->pasv_listen_fd,&tmp_data_addr.un.u_sockaddr,&len);
if(-1 == p_thesession->pasv_data_fd)
{
perror("APPE accept client_id");
}
close(p_thesession->pasv_listen_fd);
tmp_data_fd=p_thesession->pasv_data_fd;
}
unsigned long int i=0;
while (read_count=read(tmp_data_fd, data_buf, len))
{
i++;
if (!(i%myftp_conf.file_trans_rate))
usleep(50*10000+50*10000-10*1000);//这个限速比较精确,浮动范围为-1%~+1%
unsigned int write_count=write(stor_file, data_buf, read_count);
read_sum+=read_count;//统计传输数据的大小,单位为字节。
memset(data_buf, 0, len);
}
close(stor_file);
write(p_thesession->cmd_cntl_fd, "226 File receive OK.\r\n", strlen("226 File receive OK.\r\n"));
close(p_thesession->cmd_cntl_fd);
close(tmp_data_fd);
sigval_t val;
val.sival_int=read_sum;
if(sigqueue(getppid(),SIGUSR1,val)==-1)//利用发送信号函数sigqueue将统计的数据通过该函数的第3个参数传递给父进程,即传递给控制连接进程
{
die("upload sigqueue error\n");
}
exit(0);
default:
close(stor_file);
p_thesession->up_file_num=++file_num;
p_thesession->data_trans_child_pid=trans_file_fd;
close(p_thesession->pasv_data_fd);
close(p_thesession->port_data_fd);
return -1;
}
}
/*=================================================================================
function:REST重新开始传输数据命令解释函数
注:REST命令后的那个参数即为文件传输的开始位置。特例:REST 100命令专用于测试服务器是否支持断点续传
=================================================================================*/
int myftp_cmd_handle_rest(pMYFTP_SESSION p_thesession)
{
if (*p_thesession->user_str=='\0'||*p_thesession->passwd_str==0)
{
write(p_thesession->cmd_cntl_fd,"530 Not logged in.\r\n", strlen("530 Not logged in.\r\n"));
return -1;
}
char p_str[512]={0};
sprintf(p_str, "350 Restart position accepted (%s).\r\n", p_thesession->p_cmd_line->arg);
p_thesession->transfile_start_pos = (unsigned long)atoi(p_thesession->p_cmd_line->arg);
write(p_thesession->cmd_cntl_fd, p_str, strlen(p_str));
return -1;
}
/*=================================================================================
function:从相对路径中查找文件名
=================================================================================*/
char* myftp_find_fname_inpath(char* path)
{
int len=strlen(path);
path+=len-1;
while (*path!='/')
{
path--;
}
path++;
return path;
}
/*=================================================================================
function:RNFR文件重命名命令解释函数
注:RNFR命令应该与RNTO命令联合使用
=================================================================================*/
int myftp_cmd_handle_rnfr(pMYFTP_SESSION p_thesession)
{
if (*p_thesession->user_str=='\0'||*p_thesession->passwd_str==0)
{
write(p_thesession->cmd_cntl_fd,"530 Not logged in.\r\n", strlen("530 Not logged in.\r\n"));
return -1;
}
if (p_thesession->is_anonymous)//默认匿名用户不允许重命名文件
{
write(p_thesession->cmd_cntl_fd, "550 Permission denied.\r\n",strlen("550 Permission denied.\r\n"));
return -1;
}
strcpy(p_thesession->old_path_rnfr, p_thesession->p_cmd_line->arg);
char *p_str="350 Ready for RNTO.\r\n";
write(p_thesession->cmd_cntl_fd, p_str, strlen(p_str));
return -1;
}
/*=================================================================================
function:RNTO文件重命名为命令解释函数
注:RNTO命令必须与RNFR命令联合使用
=================================================================================*/
int myftp_cmd_handle_rnto(pMYFTP_SESSION p_thesession)
{
if (*p_thesession->user_str=='\0'||*p_thesession->passwd_str==0)
{
write(p_thesession->cmd_cntl_fd,"530 Not logged in.\r\n", strlen("530 Not logged in.\r\n"));
return -1;
}
if (*p_thesession->p_cmd_line->arg != '/')
{
if (!rename(p_thesession->old_path_rnfr, p_thesession->p_cmd_line->arg))
goto SUCCESS;
else
goto FAIL;
}
else if (*p_thesession->p_cmd_line->arg == '/')//客户端有输入路径,默认输入的路径即为当前工作路径,客户端有输入路径时,不知为什重命名失败。
{//客户端有输入路径时,变量p_thesession->old_path_rnfr的值居然被无故的修改了。\
好不容易发现原因:原来是p_thesession->p_cmd_line内容在每次执行完后,没有完全清理干净。
char* new_fname=myftp_find_fname_inpath(p_thesession->p_cmd_line->arg);
char* old_fname=myftp_find_fname_inpath(p_thesession->old_path_rnfr);
if (!rename(old_fname,new_fname))
goto SUCCESS;
else
goto FAIL;
}
SUCCESS:
memset(p_thesession->old_path_rnfr,0,MAX_PATH);
write(p_thesession->cmd_cntl_fd, "250 Rename successful.\r\n", strlen("250 Rename successful.\r\n"));
return -1;
FAIL:
write(p_thesession->cmd_cntl_fd, "550 Rename failed.\r\n",strlen("550 Rename failed.\r\n"));
return -1;
}
/*=================================================================================
function:ABOR终止数据传输命令解释函数
=================================================================================*/
int myftp_cmd_handle_abor(pMYFTP_SESSION p_thesession)
{
if (*p_thesession->user_str=='\0'||*p_thesession->passwd_str==0)
{
write(p_thesession->cmd_cntl_fd,"530 Not logged in.\r\n", strlen("530 Not logged in.\r\n"));
return -1;
}
if ( 0 == p_thesession->data_trans_child_pid)//当没有文件在传输过程中时
{
write(p_thesession->cmd_cntl_fd,"225 No transfer to ABOR.\r\n", strlen("225 No transfer to ABOR.\r\n"));
return -1;
}
else
{
char file_name[512]={0};
sprintf(file_name,"426 Data connection closed, file transfer %s aborted by client.\r\n",p_thesession->cur_file_name);
write(p_thesession->cmd_cntl_fd,file_name,strlen(file_name));
write(p_thesession->cmd_cntl_fd,"226 ABOR command successful.\r\n",strlen("226 ABOR command successful.\r\n"));
p_thesession->data_trans_child_pid=0;
return -1;
}
}
/*=================================================================================
function:删除文件命令解释函数
=================================================================================*/
int myftp_cmd_handle_dele(pMYFTP_SESSION p_thesession)
{
if (*p_thesession->user_str=='\0'||*p_thesession->passwd_str==0)
{
write(p_thesession->cmd_cntl_fd,"530 Not logged in.\r\n", strlen("530 Not logged in.\r\n"));
return -1;
}
if (!unlink(p_thesession->p_cmd_line->arg))
{
write(p_thesession->cmd_cntl_fd, "250 Delete operation successful.\r\n", strlen("250 Delete operation successful.\r\n"));
}
else
{
write(p_thesession->cmd_cntl_fd, "550 Delete operation failed.\r\n", strlen("550 Delete operation failed.\r\n"));
}
return -1;
}
/*=================================================================================
function:删除目录命令解释函数
=================================================================================*/
int myftp_cmd_handle_rmd(pMYFTP_SESSION p_thesession)
{
if (*p_thesession->user_str=='\0'||*p_thesession->passwd_str==0)
{
write(p_thesession->cmd_cntl_fd,"530 Not logged in.\r\n", strlen("530 Not logged in.\r\n"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -