#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <curses.h>
#include <termios.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#define DEFAULT_FTP_PORT 21
extern int h_errno;
char user[64]; //ftp usr
char passwd[64]; //ftp passwd
//ftp server address
struct sockaddr_in ftp_server, local_host;
struct hostent * server_hostent;
int sock_control;
int mode = 1; //ftp mode, 0 is PORT, 1 is PASV;
//echo_off and echo_on for get usr password from stdin
static struct termios stored_settings;
void echo_off(void)
{
struct termios new_settings;
tcgetattr(0,&stored_settings);
new_settings = stored_settings;
new_settings.c_lflag &= (~ECHO);
tcsetattr(0,TCSANOW,&new_settings);
return;
}
void echo_on(void)
{
tcsetattr(0,TCSANOW,&stored_settings);
return;
}
void cmd_err_exit(char * err_msg, int err_code)
{
printf("%s\n", err_msg);
exit(err_code);
}
int fill_host_addr(char * host_ip_addr, struct sockaddr_in * host, int port)
{
if(port <= 0 || port > 65535)
return 254;
bzero(host, sizeof(struct sockaddr_in));
host->sin_family = AF_INET;
if(inet_addr(host_ip_addr) != -1)
{
host->sin_addr.s_addr = inet_addr(host_ip_addr);
}
else
{
if((server_hostent = gethostbyname(host_ip_addr)) != 0)
{
memcpy(&host->sin_addr, server_hostent->h_addr,\
sizeof(host->sin_addr));
}
else return 253;
}
host->sin_port = htons(port);
return 1;
}
int xconnect(struct sockaddr_in *s_addr, int type)
{
struct timeval outtime;
int set;
int s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0)
cmd_err_exit("creat socket error!", 249);
//set outtime for the control socket
if(type == 1)
{
outtime.tv_sec = 0;
outtime.tv_usec = 300000;
}
else
{
outtime.tv_sec = 5;
outtime.tv_usec = 0;
}
set = setsockopt(s, SOL_SOCKET,SO_RCVTIMEO, &outtime,sizeof(outtime));
if(set !=0)
{
printf("set socket %s errno:%d\n",strerror(errno),errno);
cmd_err_exit("set socket", 1);
}
//connect to the server
if (connect(s,(struct sockaddr *)s_addr,sizeof(struct sockaddr_in)) < 0)
{
printf("Can't connect to server %s, port %d\n",\
inet_ntoa(s_addr->sin_addr),ntohs(ftp_server.sin_port));
exit(252);
}
return s;
}
//send command to server with sock_fd
int ftp_send_cmd(const char *s1, const char *s2, int sock_fd)
{
char send_buf[256];
int send_err, len;
if(s1)
{
strcpy(send_buf,s1);
if(s2)
{
strcat(send_buf, s2);
strcat(send_buf,"\r\n");
len = strlen(send_buf);
send_err = send(sock_fd, send_buf, len, 0);
}
else
{
strcat(send_buf,"\r\n");
len = strlen(send_buf);
send_err = send(sock_fd, send_buf, len, 0);
}
}
if(send_err < 0)
printf("send() error!\n");
return send_err;
}
//get the server's reply message from sock_fd
int ftp_get_reply(int sock_fd)
{
static int reply_code = 0,count=0;
char rcv_buf[512];
count=read(sock_fd, rcv_buf, 510);
if(count > 0)
reply_code = atoi(rcv_buf);
else
return 0;
while(1)
{
if(count <= 0)
break;
rcv_buf[count]='\0';
printf("%s",rcv_buf);
count=read(sock_fd, rcv_buf, 510);
}
return reply_code;
}
int get_port()
{
char port_respond[512];
char *buf_ptr;
int count,port_num;
ftp_send_cmd("PASV",NULL,sock_control);
count = read(sock_control, port_respond, 510);
if(count <= 0)
return 0;
port_respond[count]='\0';
if(atoi(port_respond) == 227)
{
//get low byte of the port
buf_ptr = strrchr(port_respond, ',');
port_num = atoi(buf_ptr + 1);
*buf_ptr = '\0';
//get high byte of the port
buf_ptr = strrchr(port_respond, ',');
port_num += atoi(buf_ptr + 1) * 256;
return port_num;
}
return 0;
}
int rand_local_port()
{
int local_port;
srand((unsigned)time(NULL));
local_port = rand() % 40000 + 1025;
return local_port;
}
//connect data stream
int xconnect_ftpdata()
{
if(mode)
{
int data_port = get_port();
if(data_port != 0)
ftp_server.sin_port=htons(data_port);
return(xconnect(&ftp_server, 0));
}
else
{
int client_port, get_sock, opt, set;
char cmd_buf[32];
struct timeval outtime;
struct sockaddr_in local;
char local_ip[24];
char *ip_1, *ip_2, *ip_3, *ip_4;
int addr_len = sizeof(struct sockaddr);
client_port = rand_local_port();
get_sock = socket(AF_INET, SOCK_STREAM, 0);
if(get_sock < 0)
{
cmd_err_exit("socket()", 1);
}
//set outtime for the data socket
outtime.tv_sec = 7;
outtime.tv_usec = 0;
opt = SO_REUSEADDR;
set = setsockopt(get_sock, SOL_SOCKET,SO_RCVTIMEO, \
&outtime,sizeof(outtime));
if(set !=0)
{
printf("set socket %s errno:%d\n",strerror(errno),errno);
cmd_err_exit("set socket", 1);
}
set = setsockopt(get_sock, SOL_SOCKET,SO_REUSEADDR, \
&opt,sizeof(opt));
if(set !=0)
{
printf("set socket %s errno:%d\n",strerror(errno),errno);
cmd_err_exit("set socket", 1);
}
bzero(&local_host,sizeof(local_host));
local_host.sin_family = AF_INET;
local_host.sin_port = htons(client_port);
local_host.sin_addr.s_addr = htonl(INADDR_ANY);
bzero(&local, sizeof(struct sockaddr));
while(1)
{
set = bind(get_sock, (struct sockaddr *)&local_host, \
sizeof(local_host));
if(set != 0 && errno == 11)
{
client_port = rand_local_port();
continue;
}
set = listen(get_sock, 1);
if(set != 0 && errno == 11)
{
cmd_err_exit("listen()", 1);
}
//get local host's ip
if(getsockname(sock_control,(struct sockaddr*)&local,\
(socklen_t *)&addr_len) < 0)
return -1;
snprintf(local_ip, sizeof(local_ip), inet_ntoa(local.sin_addr));
//change the format to the PORT command needs.
local_ip[strlen(local_ip)]='\0';
ip_1 = local_ip;
ip_2 = strchr(local_ip, '.');
*ip_2 = '\0';
ip_2++;
ip_3 = strchr(ip_2, '.');
*ip_3 = '\0';
ip_3++;
ip_4 = strchr(ip_3, '.');
*ip_4 = '\0';
ip_4++;
snprintf(cmd_buf, sizeof(cmd_buf), "PORT %s,%s,%s,%s,%d,%d", \
ip_1, ip_2, ip_3, ip_4, client_port >> 8, client_port&0xff);
ftp_send_cmd(cmd_buf, NULL, sock_control);
if(ftp_get_reply(sock_control) != 200)
{
printf("Can not use PORT mode!Please use \"mode\" change to PASV mode.\n");
return -1;
}
else
return get_sock;
}
}
}
//deal with the "list" command
void ftp_list()
{
int i = 0,new_sock;
int set = sizeof(local_host);
int list_sock_data = xconnect_ftpdata();
if(list_sock_data < 0)
{
ftp_get_reply(sock_control);
printf("creat data sock error!\n");
return;
}
ftp_get_reply(sock_control);
ftp_send_cmd("LIST", NULL, sock_control);
ftp_get_reply(sock_control);
if(mode)
ftp_get_reply(list_sock_data);
else
{
while(i < 3)
{
new_sock = accept(list_sock_data, (struct sockaddr *)&local_host, \
(socklen_t *)&set);
if(new_sock == -1)
{
printf("accept return:%s errno: %d\n", strerror(errno),errno);
i++;
continue;
}
else break;
}
if(new_sock == -1)
{
printf("Sorry, you can't use PORT mode. There is something wrong when the server connect to you.\n");
return;
}
ftp_get_reply(new_sock);
close(new_sock);
}
close(list_sock_data);
ftp_get_reply(sock_control);
}
//get filename(s) from user's command
void ftp_cmd_filename(char * usr_cmd, char * src_file, char * dst_file)
{
int length, flag = 0;
int i = 0, j = 0;
char * cmd_src;
cmd_src = strchr(usr_cmd, ' ');
if(cmd_src == NULL)
{
printf("command error!\n");
return;
}
else
{