/*
* Copyright (c) www.chinaunix.net(ldap)
* All rights reserved.
*
* Filename : ftp.c
*/
#include <stdio.h>;
#include <sys/stat.h>;
#include <fcntl.h>;
#include <stdlib.h>;
#include <sys/time.h>;
#include <time.h>;
#include <unistd.h>;
#include <string.h>;
#include <signal.h>;
#include <errno.h>;
#include <sys/types.h>;
#include <sys/socket.h>;
#include <netinet/in.h>;
#include <arpa/inet.h>;
#define FTP_PORT 21
#define MAXBACKLOG 30
#define TIMEOUT 8
extern void *ssignal (int signo, void *func);
static int saferecv(int fd, char *buf, int size);
static int safesend(int fd, char *buf, int size);
static int connect_ftp(char *ip, char *username, char *password);
static int create_dataconn(int sockfd, char *localip, int localport);
static void set_timeout();
static void unset_timeout();
static void sig(int signo)
{
put_log("ERROR:capture signal %d\n", signo);
}
static void set_timeout()
{
struct itimerval value;
ssignal(SIGALRM, sig);
value.it_value.tv_sec = TIMEOUT;
value.it_value.tv_usec = 0;
value.it_interval = value.it_value;
setitimer(ITIMER_REAL, &value, NULL );
}
static void unset_timeout()
{
struct itimerval value;
ssignal(SIGALRM, SIG_IGN);
value.it_value.tv_sec = 0;
value.it_value.tv_usec = 0;
value.it_interval = value.it_value;
setitimer(ITIMER_REAL, &value, NULL );
}
static int saferecv(int fd, char *buf, int size)
{
int ret;
set_timeout();
if ((ret = recv(fd, buf, size, 0)) < 0) {
put_log("ERROR:recv,%s\n", strerror(errno));
unset_timeout();
return -1;
}
unset_timeout();
return ret;
}
static int safesend(int fd, char *buf, int size)
{
int ret;
set_timeout();
if ((ret = send(fd, buf, size, 0)) < 0) {
put_log("ERROR:send,%s\n", strerror(errno));
unset_timeout();
return -1;
}
unset_timeout();
return ret;
}
static int connect_ftp(char *ip, char *username, char *password)
{
int sockfd, port;
struct sockaddr_in server;
char buff[1024];
port = FTP_PORT;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
put_log("ERROR:socket,%s\n", strerror(errno));
return -1;
}
server.sin_family = AF_INET;
server.sin_port = htons((unsigned short)port);
server.sin_addr.s_addr = inet_addr(ip);
set_timeout();
if (connect(sockfd, (struct sockaddr *)&server , sizeof(server)) == -1)
{
put_log("ERROR:socket,%s\n", strerror(errno));
unset_timeout();
alarm(0);
signal(SIGALRM, SIG_IGN);
close(sockfd);
return -1;
}
unset_timeout();
memset(buff, 0, sizeof(buff));
if (saferecv(sockfd, buff, sizeof(buff)) < 0) {
close(sockfd);
return -1;
}
if (strstr(buff, "220") == NULL) {
put_log("ERROR:connection refused by remote ftp server\n");
close(sockfd);
return -1;
}
memset(buff, 0, sizeof(buff));
sprintf(buff, "USER %s\r\n", username);
if (safesend(sockfd, buff, strlen(buff)) < 0) {
close(sockfd);
return -1;
}
memset(buff, 0, sizeof(buff));
if (saferecv(sockfd, buff, sizeof(buff)) < 0) {
close(sockfd);
return -1;
}
if (strstr(buff, "331") == NULL) {
put_log("ERROR:connection refused by remote ftp server\n");
close(sockfd);
return -1;
}
memset(buff, 0, sizeof(buff));
sprintf(buff, "PASS %s\r\n", password);
if (safesend(sockfd, buff, strlen(buff)) < 0) {
close(sockfd);
return -1;
}
memset(buff, 0, sizeof(buff));
if (saferecv(sockfd, buff, sizeof(buff)) < 0) {
close(sockfd);
return -1;
}
if (strstr(buff, "230") == NULL) {
put_log("ERROR:username and password not match\n");
close(sockfd);
return -1;
}
memset(buff, 0, sizeof(buff));
sprintf(buff, "SYST\r\n");
if (safesend(sockfd, buff, strlen(buff)) < 0) {
close(sockfd);
return -1;
}
memset(buff, 0, sizeof(buff));
if (saferecv(sockfd, buff, sizeof(buff)) < 0) {
close(sockfd);
return -1;
}
memset(buff, 0, sizeof(buff));
sprintf(buff, "TYPE I\r\n");
if (safesend(sockfd, buff, strlen(buff)) < 0) {
close(sockfd);
return -1;
}
memset(buff, 0, sizeof(buff));
if (saferecv(sockfd, buff, sizeof(buff)) < 0) {
close(sockfd);
return -1;
}
return sockfd;
}
static int create_dataconn(int sockfd, char *localip, int localport)
{
int on = 1, l_i;
int localsock;
struct sockaddr_in localserver;
if((localsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
put_log("ERROR:socket,%s\n", strerror(errno));
close(sockfd);
return -1;
}
if (setsockopt(localsock, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on)) == -1) {
put_log("ERROR:setsockopt,%s\n", strerror(errno));
close(sockfd);
close(localsock);
return -1;
}
localserver.sin_family = AF_INET;
localserver.sin_addr.s_addr = INADDR_ANY;
localserver.sin_port = htons((unsigned short)localport);
if ((bind(localsock, (struct sockaddr *)&localserver, sizeof(localserver)) == -1) ||
(listen(localsock, MAXBACKLOG) == -1)) {
put_log("ERROR:%s\n", strerror(errno));
put_log("ERROR:Unable to establish port %d connection\n", localport % 65536);
close(sockfd);
close(localsock);
return -1;
}
if (get_localip(localip) == -1) {
put_log("ERROR:get_localip\n");
close(sockfd);
close(localsock);
return -1;
}
for (l_i = 0; l_i < strlen (localip); l_i++)
if (localip[l_i] == '.')
localip[l_i] = ',';
return localsock;
}
int download(char *ftpserver, char *username, char *password, char *filename)
{
int sockfd, localsock, dsock;
int localport, len, i, j, k;
int fd;
struct sockaddr_in remote;
int remote_len;
char buff[1024];
char localip[256] = "10.10.17.169";
char temp[32];
int dwRead;
int dw;
if ((sockfd = connect_ftp(ftpserver, username, password)) == -1) {
put_log("ERROR:connect_ftp\n");
return -1;
}
/*get random seed*/
srand ((double) time (NULL) * 1000000);
/*use random number as port for ftpdata bind*/
localport = (rand () % 20000) + 2000;
if ((localsock = create_dataconn(sockfd, localip, localport)) == -1) {
put_log("ERROR:connect_ftp\n");
return -1;
}
memset(buff, 0, sizeof(buff));
sprintf(buff, "PORT %s,%d,%d\r\n", localip, localport / 256, localport % 256);
if (safesend(sockfd, buff, strlen(buff)) < 0)
{
close(sockfd);
close(localsock);
return -1;
}
memset(buff, 0, sizeof(buff));
if (saferecv(sockfd, buff, sizeof(buff)) < 0) {
close(sockfd);
return -1;
}
if (strstr(buff, "200") == NULL) {
put_log("ERROR:Unable to get valid data\n");
close(sockfd);
close(localsock);
return -1;
}
memset(buff, 0, sizeof(buff));
sprintf (buff, "SIZE %s\r\n", filename);
if (safesend (sockfd, buff, strlen(buff)) < 0)
{
close (sockfd);
close (localsock);
return -1;
}
memset(buff, 0, sizeof(buff));
if (saferecv(sockfd, buff, sizeof(buff)) < 0) {
close(sockfd);
close(localsock);
return -1;
}
if (strstr(buff, "550") != NULL) {
put_log("ERROR:not exist upgrade package\n");
close(sockfd);
close(localsock);
return -1;
}
len = strlen(buff);
for (i = 0; i < len; i++)
{
if (buff[i] == ' ')
{
k = 0;
for (j = i + 1; j < len; j++)
{
if ((buff[j] >;= 48) && (buff[j] <= 57))
temp[k] = buff[j];
k++;
}
break;
}
}
len = atoi (temp);
memset(buff, 0, sizeof(buff));
sprintf(buff, "RETR %s\r\n", filename);
if (safesend(sockfd, buff, strlen(buff)) < 0)
{
close (sockfd);
close (localsock);
return -1;
}
memset(buff, 0, sizeof(buff));
if (saferecv(sockfd, buff, sizeof(buff)) < 0) {
close(sockfd);
close(localsock);
return -1;
}
if (strstr(buff, "150") == NULL) {
put_log("ERROR:Unable to get valid data\n");
close(sockfd);
close(localsock);
return -1;
}
if ((dsock = accept (localsock, (struct sockaddr *) &remote, &remote_len)) == -1) {
put_log("ERROR:accept,%s\n", strerror(errno));
close(sockfd);
close(localsock);
return -1;
}
close(localsock);
if ((fd = open(filename, O_WRONLY|O_CREAT, 0644)) == -1) {
put_log("ERROR:open,%s\n", strerror(errno));
close (sockfd);
close (dsock);
return -1;
}
dwRead = 0;
dw = 0;
while (dwRead < len)
{
memset(buff, 0, sizeof(buff));
dw = saferecv(dsock, buff, sizeof(buff));
if (dw < 0)
{
close (sockfd);
close (dsock);
return -1;
}
else if (dw == 0)
break;
write(fd, buff, dw);
dwRead += dw;
}
close(fd);
memset(buff, 0, sizeof(buff));
saferecv(dsock, buff, sizeof(buff));
close(dsock);
sprintf(buff, "QUIT\r\n");
safesend(sockfd, buff, strlen(buff));
saferecv(sockfd, buff, sizeof(buff));
close(sockfd);
if (dwRead == len)
return 0;
return -1;
}
int upload(char *ftpserver, char *username, char *password, char *filename)
{
int sockfd, localsock, dsock;
int localport;
int fd;
struct sockaddr_in remote;
int remote_len;
char buff[1024];
char localip[256] = "10.10.17.169";
int dwRead;
int dw;
if ((sockfd = connect_ftp(ftpserver, username, password)) == -1) {
put_log("ERROR:connect_ftp\n");
return -1;
}
/*get random seed*/
srand ((double) time (NULL) * 1000000);
/*use random number as port for ftpdata bind*/
localport = (rand () % 20000) + 2000;
if ((localsock = create_dataconn(sockfd, localip, localport)) == -1) {
put_log("ERROR:connect_ftp\n");
return -1;
}
memset(buff, 0, sizeof(buff));
sprintf(buff, "PORT %s,%d,%d\r\n", localip, localport / 256, localport % 256);
if (safesend(sockfd, buff, strlen(buff)) < 0)
{
close(sockfd);
close(localsock);
return -1;
}
memset(buff, 0, sizeof(buff));
if (saferecv(sockfd, buff, sizeof(buff)) < 0) {
close(sockfd);
return -1;
}
if (strstr(buff, "200") == NULL) {
put_log("ERROR:Unable to get valid data\n");
close(sockfd);
close(localsock);
return -1;
}
memset(buff, 0, sizeof(buff));
sprintf (buff, "STOR %s\r\n", filename);
if (safesend (sockfd, buff, strlen(buff)) < 0)
{
close (sockfd);
close (localsock);
return -1;
}
memset(buff, 0, sizeof(buff));
if (saferecv(sockfd, buff, sizeof(buff)) < 0) {
close(sockfd);
close(localsock);
return -1;
}
if (strstr(buff, "150") == NULL) {
put_log("ERROR:Unable to get valid data\n");
close(sockfd);
close(localsock);
return -1;
}
if ((dsock = accept (localsock, (struct sockaddr *) &remote, &remote_len)) == -1) {
put_log("ERROR:accept,%s\n", strerror(errno));
close(sockfd);
close(localsock);
return -1;
}
close(localsock);
if ((fd = open(filename, O_RDONLY)) == -1) {
put_log("ERROR:open,%s\n", strerror(errno));
close (sockfd);
close (dsock);
return -1;
}
dwRead = 0;
dw = 0;
while (1)
{
memset(buff, 0, sizeof(buff));
dwRead = read(fd, buff, sizeof(buff));
if (dwRead <= 0) {
break;
}
dw = safesend(dsock, buff, dwRead);
if (dw < 0)
{
close (sockfd);
close (dsock);
return -1;
}
if (dwRead != sizeof(buff)) {
break;
}
}
close(fd);
close(dsock);
memset(buff, 0, sizeof(buff));
saferecv(sockfd, buff, sizeof(buff));
while (strstr (buff, "226") == NULL)
{
memset(buff, 0, sizeof(buff));
saferecv(sockfd, buff, sizeof(buff));
}
sprintf(buff, "QUIT\r\n");
safesend(sockfd, buff, strlen(buff));
saferecv(sockfd, buff, sizeof(buff));
close(sockfd);
return 0;
}[/code]
下有一个用C语言编写的简单ftp客户端源程序,里面很多功能都没有实现,主要有3个。1: 实现连接,断开,并且重新连接到ftp功能。2:实现DIR功能。 3: 实现RETR的功能。程序如下
//159.334 - Networks - 2/2004
//This example is NOT fully functional
//It may even require small changes to compile.
//Please refer to the sockets material and examples
//(compare this code with serv1.c and client.c codes)
//
//To connect use an FTP client. The port is 1221. To connect locally issue the following command:
//#ftp 127.0.0.1 1221
//
//Includes
#include
#include
#include
//Defines
#define WSVERS MAKEWORD(2,0)
WSADATA wsadata;
#define STKSIZE 16536
char sbuffer[80],rbuffer[80];//send and receive buffers
int n,bytes;//counters
SOCKET ns,ns_data;//sockets, ns is a new socket (on 1221) and ns_data is a new socket for data (1220)
struct sockaddr_in remoteaddr, remoteaddr_data;
//MAIN
main(int argc, char *argv[]) {
struct sockaddr_in localaddr;//local address structure
struct sockaddr_in local_data_addr;//local address struct for data connection
int s,s_data;//welcome socket and welcome socket for data connection
int addrlen;//address lenght variable
if (WSAStartup(WSVERS, &wsadata) != 0) {
WSACleanup();
printf("WSAStartup failed\n");
}
memset(&localaddr,0,sizeof(localaddr));//clear localaddr
memset(&local_data_addr,0,sizeof(local_data_addr));//clear local_data_addr
//SOCKETS (notice that there are two welcome sockets, one for control, one for data
s = socket(PF_INET, SOCK_STREAM, 0);
s_data = socket(PF_INET, SOCK_STREAM, 0);
if (s < 0) {
error("socket failed\n");
}
localaddr.sin_family = AF_INET;
local_data_addr.sin_family = AF_INET;
if (argc == 2) localaddr.sin_port = htons((u_short)atoi(argv[1]));
else localaddr.sin_port = htons(1221);
localaddr.sin_addr.s_addr = INADDR_ANY;
local_data_addr.sin_port = htons(1220);
local_data_addr.sin_addr.s_addr = INADDR_ANY;
//BIND (bind uses ports 1221 and 1220 by default)
if (bind(s,(struct sockaddr *)(&localaddr),sizeof(localaddr)) < 0) {
error("Bind failed!\n");
}
if (bind(s_data,(struct sockaddr *)(&local_data_addr),sizeof(local_data_addr)) < 0) {
error("Bind failed!\n");
}
//LISTEN
listen(s,5);
listen(s_data,5);
//INFINITE LOOP
while (1) {
addrlen = sizeof(remoteaddr);
//ACCEPT main connection (control connection)
ns = accept(s,(struct sockaddr *)(&remoteaddr),&addrlen);
printf("connected to %s\n",inet_ntoa(remoteaddr.sin_addr));
//Respond with welcome message, FTP client requires those
sprintf(sbuffer,"200 Welcome \r\n");
bytes = send(ns, sbuffer, strlen(sbuffer), 0);
sprintf(sbuffer,"530 Log in \r\n");
bytes = send(ns, sbuffer, strlen(sbuffer), 0);
sprintf(sbuffer,"530 Log in \r\n");
bytes = send(ns, sbuffer, strlen(sbuffer), 0);
//INFINITE LOOP
while (1) {
n = 0;
while (1) {
//RECEIVE
bytes = recv(ns, &rbuffer[n], 1, 0);
if ((bytes < 0) || (bytes == 0)) break;
if (rbuffer[n] == '\n') { /*end on LF*/
rbuffer[n] = '\0';
break;
}
if (rbuffer[n] != '\r') n++; /*ignore CR's*/
}
if ((bytes < 0) || (bytes == 0)) break;
printf("#The Server receives:# '%s' from client \n", rbuffer);
//STARTS INTERPRETATION OF THE FTP COMMANDS HERE
//Perhaps use "case" or "if/else" for this part
//It is a good idea to 'trap' any mistaken or non-implemented command returning "500 Syntax error" code
//
//USER
if (strncmp(rbuffer,"USER",4)==0) {
printf("Logging in \n");
sprintf(sbuffer,"331 Password required (anything will do really... :-) \r\n");
bytes = send(ns, sbuffer, strlen(sbuffer), 0);
}
//PASS
if (strncmp(rbuffer,"PASS",4)==0) {
printf("Typing password (anything will do... \n");
sprintf(sbuffer, "230 Public logging in ok, 无效 your email for password \r\n");
//sprintf(sbuffer, "230 Public logging in ok, 无效 your email for password \r\n");
bytes = send(ns, sbuffer, strlen(sbuffer), 0);
}
//SYST
if (strncmp(rbuffer,"SYST",4)==0) {
printf("Information about the system \n");
sprintf(sbuffer, "257 A very naive FTP system... \r\n");
bytes = send(ns, sbuffer, strlen(sbuffer), 0);
}
//PASV
if (strncmp(rbuffer,"PASV",4)==0) {
printf("Passive mode \n");
//change the IP address here if you want to connect from a remote machine
//227 has a strange format, for IP 127.0.0.1 and port 1220 this is it...)
sprintf(sbuffer, "227 Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",127,0,0,1,(1220>>8),(1220 & 0x00FF));
bytes = send(ns, sbuffer, strlen(sbuffer), 0);
//open a new connection on port 1220
ns_data = accept(s_data,(struct sockaddr *)(&remoteaddr_data),&addrlen);
printf("connected to %s\n",inet_ntoa(remoteaddr.sin_addr));
}
//LIST
if (strncmp(rbuffer,"LIST",4)==0) {
printf("Equivalent to dir \n");
system("ls > tmp.txt");
FILE *fin=fopen("tmp.txt","r");
sprintf(sbuffer, "125 Transfering... \r\n");
bytes = send(ns, sbuffer, strlen(sbuffer), 0);
char temp_buffer[80];
while (!feof(fin)){
fgets(temp_buffer,78,fin);
sprintf(sbuffer,"%s ",temp_buffer);
send(ns_data, sbuffer, strlen(sbuffer), 0);
}
fclose(fin);
sprintf(sbuffer, "226 Transfer completed... \r\n");
bytes = send(ns, sbuffer, strlen(sbuffer), 0);
system("del tmp.txt");
//CLOSE DATA SOCKET
close(ns_data);
}
//QUIT
if (strncmp(rbuffer,"QUIT",3)==0) {
printf("quit \n");
sprintf(sbuffer, "221 Bye bye ... \r\n");
bytes = send(ns, sbuffer, strlen(sbuffer), 0);
close(ns);
printf("disconnected from %s\n",inet_ntoa(remoteaddr.sin_addr));
return;
}
}
//CLOSE CONTROL SOCKET
close(ns);
printf("disconnected from %s\n",inet_ntoa(remoteaddr.sin_addr));
}
//CLOSE WELCOME SOCKET
close(s);
return 0;
}