/* achieve base function of ftp client.Maybe some bugs are in the file,
* if you know how to correct them,please tell me,thank you!
* All rights reserved.
* Author : xiaoleng
* Email : flylgh@163.com
* create time: 2008-11-1
*
* 实现FTP客户端基本功能,或者本实现有潜在错误,
* 如果你知道如何改正,或者你有更好的建议,请通知我。
* 对你无私的精神,我表示衷心的感谢!
* 你可以随意发布、修改,但请别用于学习或者交流的其他
* 用途!
* 作者: xiaoleng
* Email : flylgh@163.com
* 创建时间: 2008-11-1
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <dirent.h>
#include "common.h"
#include "ftpclient.h"
#include "debug.h"
#define FTP_RES_BUF_SIZE 2048
static char server_response[FTP_RES_BUF_SIZE];
static uint32 first_recv = TRUE;
static char server_ip[16];
static uint16 server_port;
static void setlock(int fd,int flag)
{
int file_flag;
file_flag = fcntl(fd,F_GETFD);
if(flag == FALSE){
fcntl(fd,F_SETFD, file_flag |O_NONBLOCK);
}
else{
fcntl(fd,F_SETFD, file_flag & ~O_NONBLOCK);
}
}
static void get_server_info(char *svr_ip,uint16 *server_port)
{
char *p1,*p2;
uint8 high_byte,low_byte;
char tmp[FTP_RES_BUF_SIZE];
int i = 4;
p1 = strchr(server_response,'(')+1;
p2 = strchr(server_response,')')-1;
strncpy(tmp,p1,p2-p1+1);
tmp[p2-p1+1] = '\0';
p1 = tmp;
while(i){
while(*p1 != ','){
*svr_ip++ = *p1++;
}
if(i == 1){
*svr_ip++ = '\0';
}else{
*svr_ip++ = '.';
}
p1++;
i--;
}
p2 = p1;
while(*p2 != ',') p2++;
low_byte = atoi(++p2);
*(--p2) = '\0';
high_byte = atoi(p1);
*server_port = (high_byte<<8) + low_byte;
}
static int send_cmd(char *cmd,ftpc_ctrl *ftp_info)
{
if(send(ftp_info->ctrl_fd,cmd,strlen(cmd),0) == -1){
return -1;
}
return 0;
}
static int recv_response(ftpc_ctrl *ftp_info)
{
int n_read,retval;
fd_set readfd;
struct timeval timeout;
char res_code[4]={0};
FD_ZERO(&readfd);
FD_SET(ftp_info->ctrl_fd,&readfd);
timeout.tv_sec = FTPC_RECV_TIMEOUT;
timeout.tv_usec = 0;
retval = select(ftp_info->ctrl_fd + 1,&readfd,NULL,NULL,&timeout);
if(retval == -1){
return -1;
}
else if(retval == 0){
debug_print("receive response from server time out!\n");
return -1;
}
else{
n_read = recv(ftp_info->ctrl_fd,server_response,FTP_RES_BUF_SIZE,0);
if((n_read==-1) || (n_read==0)){
return -1;
}
server_response[n_read-1] = '\0';
server_response[n_read-2] = '\0';
}
strncpy(res_code,server_response,3);
return atoi(res_code);
}
static int get_res_code(void)
{
char buf[4] = {0};
strncpy(buf,server_response,3);
return atoi(buf);
}
static void ftpc_help(void)
{
sprintf(server_response,
"These commands below are surported:\n"
"%-10s %-10s %-10s %-10s %-10s\n"
"%-10s %-10s %-10s %-10s %-10s\n"
"%-10s %-10s %-10s ",
"ls","lcd","put","get","rmdir",
"mkdir","del","dir","quit","bye",
"pwd","localshow","help"
);
}
static int go_passive(ftpc_ctrl *ftp_info)
{
ftp_info->open_mode = MODE_PASSIVE;
send_cmd("PASV\r\n",ftp_info);
if(recv_response(ftp_info) != 227){
return -1;
}
printf("%s\n",server_response);
get_server_info(server_ip,&server_port);
return 0;
}
static int deal_cmd_lcshow(void)
{
char cur_dir[128],buf[80];
int i = 0,len;
int spare_dot = 80;
DIR *dir;
struct dirent *ptr;
memset(server_response,0,sizeof(server_response));
getcwd(cur_dir,sizeof(cur_dir));
dir = opendir(cur_dir);
while((ptr=readdir(dir)) != NULL){
sprintf(buf,"[%s] ",ptr->d_name);
len = strlen(buf);
if(spare_dot > len){
strcat(server_response,buf);
spare_dot -= len;
}
else{
strcat(server_response,"\n");
strcat(server_response,buf);
spare_dot = 80-len;
}
i++;
}
closedir(dir);
sprintf(buf,"\nTotal %d files at local",i);
strcat(server_response,buf);
return 0;
}
static int deal_cmd_lcd(char *param,ftpc_ctrl *ftp_info)
{
int retval;
char cur_dir[128];
getcwd(cur_dir,sizeof(cur_dir));
if(*param == '\0'){
sprintf(server_response,"now dir is [%s]",cur_dir);
return 0;
}
retval = chdir(param);
getcwd(cur_dir,sizeof(cur_dir));
if(retval == 0){
sprintf(server_response,"now dir is [%s]",cur_dir);
}
else{
strcpy(server_response,"change directory error!");
}
return retval;
}
static int send_data(char *pdata,ftpc_ctrl *ftp_info,int n_send)
{
int retval,maxfd;
int n_data = 0;
fd_set writefd;
struct timeval timeout;
struct sockaddr_in sa;
if(first_recv == TRUE){
first_recv = FALSE;
if(ftp_info->open_mode == MODE_PASSIVE){
sa.sin_family = AF_INET;
sa.sin_port = htons(server_port);
sa.sin_addr.s_addr = inet_addr(server_ip);
ftp_info->data_fd = socket(AF_INET,SOCK_STREAM,0);
connect(ftp_info->data_fd,(struct sockaddr *)&sa,sizeof(sa));
}
}
if(n_send <= 0){
return 0;
}
FD_ZERO(&writefd);
FD_SET(ftp_info->data_fd,&writefd);
timeout.tv_sec = FTPC_SEND_TIMEOUT;
timeout.tv_usec = 0;
maxfd = ftp_info->data_fd + 1;
retval = select(maxfd,NULL,&writefd,NULL,&timeout);
if(retval == -1){
return -1;
}
else if(retval == 0){
debug_print("send to server time out!\n");
return -1;
}
else{
if(FD_ISSET(ftp_info->data_fd,&writefd)){
n_data = send(ftp_info->data_fd,pdata,n_send,0);
if(n_data != n_send){
printf("send data error!\n");
return -1;
}
}
}
return n_data;
}
static int recv_data(char *pdata,ftpc_ctrl *ftp_info)
{
int retval,maxfd;
int n_res = 0;
int n_data = 0;
char res_buf[64];
fd_set readfd;
struct timeval timeout;
struct sockaddr_in sa;
if(first_recv == TRUE){
first_recv = FALSE;
if(ftp_info->open_mode == MODE_PASSIVE){
sa.sin_family = AF_INET;
sa.sin_port = htons(server_port);
sa.sin_addr.s_addr = inet_addr(server_ip);
ftp_info->data_fd = socket(AF_INET,SOCK_STREAM,0);
connect(ftp_info->data_fd,(struct sockaddr *)&sa,sizeof(sa));
}
}
FD_ZERO(&readfd);
FD_SET(ftp_info->data_fd,&readfd);
FD_SET(ftp_info->ctrl_fd,&readfd);
timeout.tv_sec = FTPC_RECV_TIMEOUT;
timeout.tv_usec = 0;
maxfd = ftp_info->data_fd > ftp_info->ctrl_fd ? ftp_info->data_fd : ftp_info->ctrl_fd;
retval = select(maxfd+ 1,&readfd,NULL,NULL,&timeout);
if(retval == -1){
return -1;
}
else if(retval == 0){
debug_print("receive data from server time out!\n");
return -1;
}
else{
if(FD_ISSET(ftp_info->data_fd,&readfd)){
n_data = recv(ftp_info->data_fd,pdata,FTPC_MAX_DATA_LEN,0);
}
if(FD_ISSET(ftp_info->ctrl_fd,&readfd)){
n_res = recv(ftp_info->ctrl_fd,server_response,sizeof(server_response),0);
server_response[n_res-1] = '\0';
server_response[n_res-2] = '\0';
strcpy(res_buf,server_response);
res_buf[3] = '\0';
if(atoi(res_buf) == 226){
return n_data;
}
else{
return -1;
}
}
}
return n_data;
}
static int deal_cmd_cd(char *host_dir,ftpc_ctrl *ftp_info)
{
char cmd_line[64];
sprintf(cmd_line,"CWD %s\r\n",host_dir);
if(send_cmd(cmd_line,ftp_info) == -1){
return -1;
}
if(recv_response(ftp_info) != 250){
return -1;
}
return 0;
}
static int deal_cmd_ls(ftpc_ctrl *ftp_info)
{
int retval = 0;
char file_list[2048];
if(ftp_info->open_mode == MODE_PASSIVE){
if(go_passive(ftp_info) == -1){
return -1;
}
}
if(send_cmd("LIST\r\n",ftp_info) == -1){
return -1;
}
if(recv_response(ftp_info) != 150){
return -1;
}
printf("%s\n",server_response);
retval = recv_data(file_list ,ftp_info);
file_list[retval] = '\0';
printf("%s",file_list);
first_recv = TRUE;
close(ftp_inf
评论0