⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 myftp_state_machine.c

📁 Linux下的ftp服务器
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 + -