//==========================================================================
|
//==========================================================================
|
//
|
//
|
// ftpclient.c
|
// ftpclient.c
|
//
|
//
|
// A simple FTP client
|
// A simple FTP client
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
// -------------------------------------------
|
// -------------------------------------------
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
// Copyright (C) 2002 Andrew Lunn.
|
// Copyright (C) 2002 Andrew Lunn.
|
//
|
//
|
// eCos is free software; you can redistribute it and/or modify it under
|
// eCos is free software; you can redistribute it and/or modify it under
|
// the terms of the GNU General Public License as published by the Free
|
// the terms of the GNU General Public License as published by the Free
|
// Software Foundation; either version 2 or (at your option) any later version.
|
// Software Foundation; either version 2 or (at your option) any later version.
|
//
|
//
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// You should have received a copy of the GNU General Public License along
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
//
|
//
|
// As a special exception, if other files instantiate templates or use macros
|
// As a special exception, if other files instantiate templates or use macros
|
// or inline functions from this file, or you compile this file and link it
|
// or inline functions from this file, or you compile this file and link it
|
// with other works to produce a work based on this file, this file does not
|
// with other works to produce a work based on this file, this file does not
|
// by itself cause the resulting work to be covered by the GNU General Public
|
// by itself cause the resulting work to be covered by the GNU General Public
|
// License. However the source code for this file must still be made available
|
// License. However the source code for this file must still be made available
|
// in accordance with section (3) of the GNU General Public License.
|
// in accordance with section (3) of the GNU General Public License.
|
//
|
//
|
// This exception does not invalidate any other reasons why a work based on
|
// This exception does not invalidate any other reasons why a work based on
|
// this file might be covered by the GNU General Public License.
|
// this file might be covered by the GNU General Public License.
|
//
|
//
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// at http://sources.redhat.com/ecos/ecos-license/
|
// -------------------------------------------
|
// -------------------------------------------
|
//####ECOSGPLCOPYRIGHTEND####
|
//####ECOSGPLCOPYRIGHTEND####
|
//==========================================================================
|
//==========================================================================
|
//#####DESCRIPTIONBEGIN####
|
//#####DESCRIPTIONBEGIN####
|
//
|
//
|
// Author(s): andrew.lunn@ascom.ch
|
// Author(s): andrew.lunn@ascom.ch
|
// Contributors: andrew.lunn@ascom.ch
|
// Contributors: andrew.lunn@ascom.ch
|
// Date: 2001-11-4
|
// Date: 2001-11-4
|
// Purpose:
|
// Purpose:
|
// Description:
|
// Description:
|
//
|
//
|
//####DESCRIPTIONEND####
|
//####DESCRIPTIONEND####
|
//
|
//
|
//==========================================================================
|
//==========================================================================
|
|
|
#include <pkgconf/system.h>
|
#include <pkgconf/system.h>
|
|
|
#include <network.h>
|
#include <network.h>
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <sys/socket.h>
|
#include <sys/socket.h>
|
#include <netinet/in.h>
|
#include <netinet/in.h>
|
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
#include <ctype.h>
|
#include <ctype.h>
|
#include "ftpclient.h"
|
#include "ftpclient.h"
|
|
|
/* Build one command to send to the FTP server */
|
/* Build one command to send to the FTP server */
|
static int
|
static int
|
build_cmd(char *buf,
|
build_cmd(char *buf,
|
unsigned bufsize,
|
unsigned bufsize,
|
char *cmd,
|
char *cmd,
|
char *arg1)
|
char *arg1)
|
{
|
{
|
int cnt;
|
int cnt;
|
|
|
if (arg1) {
|
if (arg1) {
|
cnt = snprintf(buf,bufsize,"%s %s\r\n",cmd,arg1);
|
cnt = snprintf(buf,bufsize,"%s %s\r\n",cmd,arg1);
|
} else {
|
} else {
|
cnt = snprintf(buf,bufsize,"%s\r\n",cmd);
|
cnt = snprintf(buf,bufsize,"%s\r\n",cmd);
|
}
|
}
|
|
|
if (cnt < bufsize)
|
if (cnt < bufsize)
|
return 1;
|
return 1;
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
/* Read one line from the server, being careful not to overrun the
|
/* Read one line from the server, being careful not to overrun the
|
buffer. If we do reach the end of the buffer, discard the rest of
|
buffer. If we do reach the end of the buffer, discard the rest of
|
the line. */
|
the line. */
|
static int
|
static int
|
get_line(int s, char *buf, unsigned buf_size,ftp_printf_t ftp_printf) {
|
get_line(int s, char *buf, unsigned buf_size,ftp_printf_t ftp_printf) {
|
|
|
int eol = 0;
|
int eol = 0;
|
int cnt = 0;
|
int cnt = 0;
|
int ret;
|
int ret;
|
char c;
|
char c;
|
|
|
while(!eol) {
|
while(!eol) {
|
ret = read(s,&c,1);
|
ret = read(s,&c,1);
|
|
|
if (ret != 1) {
|
if (ret != 1) {
|
ftp_printf(1,"read %s\n",strerror(errno));
|
ftp_printf(1,"read %s\n",strerror(errno));
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
if (c == '\n') {
|
if (c == '\n') {
|
eol = 1;
|
eol = 1;
|
continue;
|
continue;
|
}
|
}
|
|
|
if (cnt < buf_size) {
|
if (cnt < buf_size) {
|
buf[cnt++] = c;
|
buf[cnt++] = c;
|
}
|
}
|
}
|
}
|
if (cnt < buf_size) {
|
if (cnt < buf_size) {
|
buf[cnt++] = '\0';
|
buf[cnt++] = '\0';
|
} else {
|
} else {
|
buf[buf_size -1] = '\0';
|
buf[buf_size -1] = '\0';
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Read the reply from the server and return the MSB from the return
|
/* Read the reply from the server and return the MSB from the return
|
code. This gives us a basic idea if the command failed/worked. The
|
code. This gives us a basic idea if the command failed/worked. The
|
reply can be spread over multiple lines. When this happens the line
|
reply can be spread over multiple lines. When this happens the line
|
will start with a - to indicate there is more*/
|
will start with a - to indicate there is more*/
|
static int
|
static int
|
get_reply(int s,ftp_printf_t ftp_printf) {
|
get_reply(int s,ftp_printf_t ftp_printf) {
|
|
|
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
int more = 0;
|
int more = 0;
|
int ret;
|
int ret;
|
int first_line=1;
|
int first_line=1;
|
int code=0;
|
int code=0;
|
|
|
do {
|
do {
|
|
|
if ((ret=get_line(s,buf,sizeof(buf),ftp_printf)) < 0) {
|
if ((ret=get_line(s,buf,sizeof(buf),ftp_printf)) < 0) {
|
return(ret);
|
return(ret);
|
}
|
}
|
|
|
ftp_printf(0,"FTP: %s\n",buf);
|
ftp_printf(0,"FTP: %s\n",buf);
|
|
|
if (first_line) {
|
if (first_line) {
|
code = strtoul(buf,NULL,0);
|
code = strtoul(buf,NULL,0);
|
first_line=0;
|
first_line=0;
|
more = (buf[3] == '-');
|
more = (buf[3] == '-');
|
} else {
|
} else {
|
if (isdigit(buf[0]) && isdigit(buf[1]) && isdigit(buf[2]) &&
|
if (isdigit(buf[0]) && isdigit(buf[1]) && isdigit(buf[2]) &&
|
(code == strtoul(buf,NULL,0)) &&
|
(code == strtoul(buf,NULL,0)) &&
|
buf[3]==' ') {
|
buf[3]==' ') {
|
more=0;
|
more=0;
|
} else {
|
} else {
|
more =1;
|
more =1;
|
}
|
}
|
}
|
}
|
} while (more);
|
} while (more);
|
|
|
return (buf[0] - '0');
|
return (buf[0] - '0');
|
}
|
}
|
|
|
/* Send a command to the server */
|
/* Send a command to the server */
|
static int
|
static int
|
send_cmd(int s,char * msgbuf,ftp_printf_t ftp_printf) {
|
send_cmd(int s,char * msgbuf,ftp_printf_t ftp_printf) {
|
|
|
int len;
|
int len;
|
int slen = strlen(msgbuf);
|
int slen = strlen(msgbuf);
|
|
|
if ((len = write(s,msgbuf,slen)) != slen) {
|
if ((len = write(s,msgbuf,slen)) != slen) {
|
if (slen < 0) {
|
if (slen < 0) {
|
ftp_printf(1,"write %s\n",strerror(errno));
|
ftp_printf(1,"write %s\n",strerror(errno));
|
return FTP_BAD;
|
return FTP_BAD;
|
} else {
|
} else {
|
ftp_printf(1,"write truncasted!\n");
|
ftp_printf(1,"write truncasted!\n");
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
}
|
}
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/* Send a complete command to the server and receive the reply. Return the
|
/* Send a complete command to the server and receive the reply. Return the
|
MSB of the reply code. */
|
MSB of the reply code. */
|
static int
|
static int
|
command(char * cmd,
|
command(char * cmd,
|
char * arg,
|
char * arg,
|
int s,
|
int s,
|
char *msgbuf,
|
char *msgbuf,
|
int msgbuflen,
|
int msgbuflen,
|
ftp_printf_t ftp_printf) {
|
ftp_printf_t ftp_printf) {
|
|
|
int err;
|
int err;
|
|
|
if (!build_cmd(msgbuf,msgbuflen,cmd,arg)) {
|
if (!build_cmd(msgbuf,msgbuflen,cmd,arg)) {
|
ftp_printf(1,"FTP: %s command to long\n",cmd);
|
ftp_printf(1,"FTP: %s command to long\n",cmd);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
ftp_printf(0,"FTP: Sending %s command\n",cmd);
|
ftp_printf(0,"FTP: Sending %s command\n",cmd);
|
|
|
if ((err=send_cmd(s,msgbuf,ftp_printf)) < 0) {
|
if ((err=send_cmd(s,msgbuf,ftp_printf)) < 0) {
|
return(err);
|
return(err);
|
}
|
}
|
|
|
return (get_reply(s,ftp_printf));
|
return (get_reply(s,ftp_printf));
|
}
|
}
|
|
|
/* Open a socket and connect it to the server. Also print out the
|
/* Open a socket and connect it to the server. Also print out the
|
address of the server for debug purposes.*/
|
address of the server for debug purposes.*/
|
|
|
static int
|
static int
|
connect_to_server(char *hostname,
|
connect_to_server(char *hostname,
|
struct sockaddr_in * local,
|
struct sockaddr_in * local,
|
ftp_printf_t ftp_printf)
|
ftp_printf_t ftp_printf)
|
{
|
{
|
struct sockaddr_in host;
|
struct sockaddr_in host;
|
struct servent *sent;
|
struct servent *sent;
|
#ifdef CYGPKG_NS_DNS
|
#ifdef CYGPKG_NS_DNS
|
struct hostent *hp=NULL;
|
struct hostent *hp=NULL;
|
#endif
|
#endif
|
int s, len;
|
int s, len;
|
|
|
s = socket(AF_INET, SOCK_STREAM, 0);
|
s = socket(AF_INET, SOCK_STREAM, 0);
|
if (s < 0) {
|
if (s < 0) {
|
ftp_printf(1,"socket: %s\n",strerror(errno));
|
ftp_printf(1,"socket: %s\n",strerror(errno));
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
sent = getservbyname("ftp", "tcp");
|
sent = getservbyname("ftp", "tcp");
|
if (sent == (struct servent *)0) {
|
if (sent == (struct servent *)0) {
|
ftp_printf(1,"FTP: unknown serivice\n");
|
ftp_printf(1,"FTP: unknown serivice\n");
|
close(s);
|
close(s);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
#ifdef CYGPKG_NS_DNS
|
#ifdef CYGPKG_NS_DNS
|
hp = gethostbyname(hostname);
|
hp = gethostbyname(hostname);
|
|
|
|
|
if (hp) { /* try name first */
|
if (hp) { /* try name first */
|
host.sin_family = hp->h_addrtype;
|
host.sin_family = hp->h_addrtype;
|
bcopy(hp->h_addr, &host.sin_addr, hp->h_length);
|
bcopy(hp->h_addr, &host.sin_addr, hp->h_length);
|
} else
|
} else
|
#endif
|
#endif
|
{ /* maybe it's a numeric address ?*/
|
{ /* maybe it's a numeric address ?*/
|
host.sin_family = AF_INET;
|
host.sin_family = AF_INET;
|
|
|
if (inet_aton(hostname,&host.sin_addr) == 0) {
|
if (inet_aton(hostname,&host.sin_addr) == 0) {
|
ftp_printf(1,"host not found: %s\n", hostname);
|
ftp_printf(1,"host not found: %s\n", hostname);
|
close (s);
|
close (s);
|
return FTP_NOSUCHHOST;
|
return FTP_NOSUCHHOST;
|
}
|
}
|
}
|
}
|
|
|
host.sin_port = sent->s_port;
|
host.sin_port = sent->s_port;
|
|
|
if (connect(s, (struct sockaddr *)&host, sizeof(host)) < 0) {
|
if (connect(s, (struct sockaddr *)&host, sizeof(host)) < 0) {
|
ftp_printf(1,"FTP Connect failed: %s\n",strerror(errno));
|
ftp_printf(1,"FTP Connect failed: %s\n",strerror(errno));
|
close (s);
|
close (s);
|
return FTP_NOSUCHHOST;
|
return FTP_NOSUCHHOST;
|
}
|
}
|
|
|
len = sizeof(struct sockaddr_in);
|
len = sizeof(struct sockaddr_in);
|
if (getsockname(s, (struct sockaddr *)local, &len) < 0) {
|
if (getsockname(s, (struct sockaddr *)local, &len) < 0) {
|
ftp_printf(1,"getsockname failed %s\n",strerror(errno));
|
ftp_printf(1,"getsockname failed %s\n",strerror(errno));
|
close(s);
|
close(s);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
ftp_printf(0,"FTP: Connected to %s.%d\n",
|
ftp_printf(0,"FTP: Connected to %s.%d\n",
|
inet_ntoa(host.sin_addr), ntohs(host.sin_port));
|
inet_ntoa(host.sin_addr), ntohs(host.sin_port));
|
|
|
return (s);
|
return (s);
|
}
|
}
|
|
|
/* Perform a login to the server. Pass the username and password and
|
/* Perform a login to the server. Pass the username and password and
|
put the connection into binary mode. This assumes a passwd is
|
put the connection into binary mode. This assumes a passwd is
|
always needed. Is this true? */
|
always needed. Is this true? */
|
|
|
static int
|
static int
|
login(char * username,
|
login(char * username,
|
char *passwd,
|
char *passwd,
|
int s,
|
int s,
|
char *msgbuf,
|
char *msgbuf,
|
unsigned msgbuflen,
|
unsigned msgbuflen,
|
ftp_printf_t ftp_printf) {
|
ftp_printf_t ftp_printf) {
|
|
|
int ret;
|
int ret;
|
|
|
ret = command("USER",username,s,msgbuf,msgbuflen,ftp_printf);
|
ret = command("USER",username,s,msgbuf,msgbuflen,ftp_printf);
|
if (ret != 3) {
|
if (ret != 3) {
|
ftp_printf(1,"FTP: User %s not accepted\n",username);
|
ftp_printf(1,"FTP: User %s not accepted\n",username);
|
return (FTP_BADUSER);
|
return (FTP_BADUSER);
|
}
|
}
|
|
|
ret = command("PASS",passwd,s,msgbuf,msgbuflen,ftp_printf);
|
ret = command("PASS",passwd,s,msgbuf,msgbuflen,ftp_printf);
|
if (ret < 0) {
|
if (ret < 0) {
|
return (ret);
|
return (ret);
|
}
|
}
|
if (ret != 2) {
|
if (ret != 2) {
|
ftp_printf(1,"FTP: Login failed for User %s\n",username);
|
ftp_printf(1,"FTP: Login failed for User %s\n",username);
|
return (FTP_BADUSER);
|
return (FTP_BADUSER);
|
}
|
}
|
|
|
ftp_printf(0,"FTP: Login sucessfull\n");
|
ftp_printf(0,"FTP: Login sucessfull\n");
|
|
|
ret = command("TYPE","I",s,msgbuf,msgbuflen,ftp_printf);
|
ret = command("TYPE","I",s,msgbuf,msgbuflen,ftp_printf);
|
if (ret < 0) {
|
if (ret < 0) {
|
return (ret);
|
return (ret);
|
}
|
}
|
if (ret != 2) {
|
if (ret != 2) {
|
ftp_printf(1,"FTP: TYPE failed!\n");
|
ftp_printf(1,"FTP: TYPE failed!\n");
|
return (FTP_BAD);
|
return (FTP_BAD);
|
}
|
}
|
return (ret);
|
return (ret);
|
}
|
}
|
|
|
|
|
/* Open a data socket. This is a client socket, i.e. its listening
|
/* Open a data socket. This is a client socket, i.e. its listening
|
waiting for the FTP server to connect to it. Once the socket has been
|
waiting for the FTP server to connect to it. Once the socket has been
|
opened send the port command to the server so the server knows which
|
opened send the port command to the server so the server knows which
|
port we are listening on.*/
|
port we are listening on.*/
|
static int
|
static int
|
opendatasock(int ctrl_s,
|
opendatasock(int ctrl_s,
|
struct sockaddr_in ctrl,
|
struct sockaddr_in ctrl,
|
char *msgbuf,
|
char *msgbuf,
|
unsigned msgbuflen,
|
unsigned msgbuflen,
|
ftp_printf_t ftp_printf) {
|
ftp_printf_t ftp_printf) {
|
|
|
struct sockaddr_in local;
|
struct sockaddr_in local;
|
socklen_t len;
|
socklen_t len;
|
int on = 1;
|
int on = 1;
|
char buf[4*6+1];
|
char buf[4*6+1];
|
char *a, *p;
|
char *a, *p;
|
int ret;
|
int ret;
|
int s;
|
int s;
|
|
|
s = socket(AF_INET, SOCK_STREAM, 0);
|
s = socket(AF_INET, SOCK_STREAM, 0);
|
if (s < 0) {
|
if (s < 0) {
|
ftp_printf(1,"socket: %s\n",strerror(errno));
|
ftp_printf(1,"socket: %s\n",strerror(errno));
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
|
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
|
ftp_printf(1,"setsockopt: %s\n",strerror(errno));
|
ftp_printf(1,"setsockopt: %s\n",strerror(errno));
|
close(s);
|
close(s);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
local = ctrl;
|
local = ctrl;
|
local.sin_family = AF_INET;
|
local.sin_family = AF_INET;
|
local.sin_port = 0;
|
local.sin_port = 0;
|
if (bind(s,(struct sockaddr *)&local,sizeof(local)) < 0) {
|
if (bind(s,(struct sockaddr *)&local,sizeof(local)) < 0) {
|
ftp_printf(1,"bind: %s\n",strerror(errno));
|
ftp_printf(1,"bind: %s\n",strerror(errno));
|
close(s);
|
close(s);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
len = sizeof(local);
|
len = sizeof(local);
|
if (getsockname(s,(struct sockaddr *)&local,&len) < 0) {
|
if (getsockname(s,(struct sockaddr *)&local,&len) < 0) {
|
ftp_printf(1,"getsockname: %s\n",strerror(errno));
|
ftp_printf(1,"getsockname: %s\n",strerror(errno));
|
close(s);
|
close(s);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
if (listen(s, 1) < 0) {
|
if (listen(s, 1) < 0) {
|
ftp_printf(1,"listen: %s\n",strerror(errno));
|
ftp_printf(1,"listen: %s\n",strerror(errno));
|
close(s);
|
close(s);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
#define BtoI(b) (((int)b)&0xff)
|
#define BtoI(b) (((int)b)&0xff)
|
a = (char *)&local.sin_addr;
|
a = (char *)&local.sin_addr;
|
p = (char *)&local.sin_port;
|
p = (char *)&local.sin_port;
|
sprintf(buf,"%d,%d,%d,%d,%d,%d",
|
sprintf(buf,"%d,%d,%d,%d,%d,%d",
|
BtoI(a[0]),BtoI(a[1]),BtoI(a[2]),BtoI(a[3]),
|
BtoI(a[0]),BtoI(a[1]),BtoI(a[2]),BtoI(a[3]),
|
BtoI(p[0]),BtoI(p[1]));
|
BtoI(p[0]),BtoI(p[1]));
|
|
|
ret = command("PORT",buf,ctrl_s,msgbuf,msgbuflen,ftp_printf);
|
ret = command("PORT",buf,ctrl_s,msgbuf,msgbuflen,ftp_printf);
|
if (ret < 0) {
|
if (ret < 0) {
|
close(s);
|
close(s);
|
return (ret);
|
return (ret);
|
}
|
}
|
|
|
if (ret != 2) {
|
if (ret != 2) {
|
ftp_printf(1,"FTP: PORT failed!\n");
|
ftp_printf(1,"FTP: PORT failed!\n");
|
close(s);
|
close(s);
|
return (FTP_BAD);
|
return (FTP_BAD);
|
}
|
}
|
return (s);
|
return (s);
|
}
|
}
|
|
|
/* Receive the file into the buffer and close the data socket
|
/* Receive the file into the buffer and close the data socket
|
afterwards */
|
afterwards */
|
static int
|
static int
|
receive_file(int data_s, char *buf, int buf_size,ftp_printf_t ftp_printf)
|
receive_file(int data_s, char *buf, int buf_size,ftp_printf_t ftp_printf)
|
{
|
{
|
int remaining = buf_size;
|
int remaining = buf_size;
|
int finished = 0;
|
int finished = 0;
|
int total_size=0;
|
int total_size=0;
|
char *bufp = buf;
|
char *bufp = buf;
|
int len;
|
int len;
|
int s;
|
int s;
|
|
|
s = accept(data_s,NULL,0);
|
s = accept(data_s,NULL,0);
|
if (s<0) {
|
if (s<0) {
|
ftp_printf(1,"listen: %s\n",strerror(errno));
|
ftp_printf(1,"listen: %s\n",strerror(errno));
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
do {
|
do {
|
len = read(s,bufp,remaining);
|
len = read(s,bufp,remaining);
|
if (len < 0) {
|
if (len < 0) {
|
ftp_printf(1,"read: %s\n",strerror(errno));
|
ftp_printf(1,"read: %s\n",strerror(errno));
|
close(s);
|
close(s);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
if (len == 0) {
|
if (len == 0) {
|
finished = 1;
|
finished = 1;
|
} else {
|
} else {
|
total_size += len;
|
total_size += len;
|
remaining -= len;
|
remaining -= len;
|
bufp += len;
|
bufp += len;
|
|
|
if (total_size == buf_size) {
|
if (total_size == buf_size) {
|
ftp_printf(1,"FTP: File too big!\n");
|
ftp_printf(1,"FTP: File too big!\n");
|
close(s);
|
close(s);
|
return FTP_TOOBIG;
|
return FTP_TOOBIG;
|
}
|
}
|
}
|
}
|
} while (!finished);
|
} while (!finished);
|
|
|
close(s);
|
close(s);
|
return total_size;
|
return total_size;
|
}
|
}
|
|
|
/* Receive the file into the buffer and close the socket afterwards*/
|
/* Receive the file into the buffer and close the socket afterwards*/
|
static int
|
static int
|
send_file(int data_s, char *buf, int buf_size,ftp_printf_t ftp_printf)
|
send_file(int data_s, char *buf, int buf_size,ftp_printf_t ftp_printf)
|
{
|
{
|
int remaining=buf_size;
|
int remaining=buf_size;
|
int finished = 0;
|
int finished = 0;
|
char * bufp = buf;
|
char * bufp = buf;
|
int len;
|
int len;
|
int s;
|
int s;
|
|
|
s = accept(data_s,NULL,0);
|
s = accept(data_s,NULL,0);
|
if (s<0) {
|
if (s<0) {
|
ftp_printf(1,"listen: %s\n",strerror(errno));
|
ftp_printf(1,"listen: %s\n",strerror(errno));
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
do {
|
do {
|
len = write(s,bufp,remaining);
|
len = write(s,bufp,remaining);
|
if (len < 0) {
|
if (len < 0) {
|
ftp_printf(1,"write: %s\n",strerror(errno));
|
ftp_printf(1,"write: %s\n",strerror(errno));
|
close(s);
|
close(s);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
if (len == remaining) {
|
if (len == remaining) {
|
finished = 1;
|
finished = 1;
|
} else {
|
} else {
|
remaining -= len;
|
remaining -= len;
|
bufp += len;
|
bufp += len;
|
}
|
}
|
} while (!finished);
|
} while (!finished);
|
|
|
close(s);
|
close(s);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* All done, say bye, bye */
|
/* All done, say bye, bye */
|
static int quit(int s,
|
static int quit(int s,
|
char *msgbuf,
|
char *msgbuf,
|
unsigned msgbuflen,
|
unsigned msgbuflen,
|
ftp_printf_t ftp_printf) {
|
ftp_printf_t ftp_printf) {
|
|
|
int ret;
|
int ret;
|
|
|
ret = command("QUIT",NULL,s,msgbuf,msgbuflen,ftp_printf);
|
ret = command("QUIT",NULL,s,msgbuf,msgbuflen,ftp_printf);
|
if (ret < 0) {
|
if (ret < 0) {
|
return (ret);
|
return (ret);
|
}
|
}
|
if (ret != 2) {
|
if (ret != 2) {
|
ftp_printf(1,"FTP: Quit failed!\n");
|
ftp_printf(1,"FTP: Quit failed!\n");
|
return (FTP_BAD);
|
return (FTP_BAD);
|
}
|
}
|
|
|
ftp_printf(0,"FTP: Connection closed\n");
|
ftp_printf(0,"FTP: Connection closed\n");
|
return (0);
|
return (0);
|
}
|
}
|
|
|
/* Get a file from an FTP server. Hostname is the name/IP address of
|
/* Get a file from an FTP server. Hostname is the name/IP address of
|
the server. username is the username used to connect to the server
|
the server. username is the username used to connect to the server
|
with. Passwd is the password used to authentificate the
|
with. Passwd is the password used to authentificate the
|
username. filename is the name of the file to receive. It should be
|
username. filename is the name of the file to receive. It should be
|
the full pathname of the file. buf is a pointer to a buffer the
|
the full pathname of the file. buf is a pointer to a buffer the
|
contents of the file should be placed in and buf_size is the size
|
contents of the file should be placed in and buf_size is the size
|
of the buffer. If the file is bigger than the buffer, buf_size
|
of the buffer. If the file is bigger than the buffer, buf_size
|
bytes will be retrieved and an error code returned. ftp_printf is a
|
bytes will be retrieved and an error code returned. ftp_printf is a
|
function to be called to perform printing. On success the number of
|
function to be called to perform printing. On success the number of
|
bytes received is returned. On error a negative value is returned
|
bytes received is returned. On error a negative value is returned
|
indicating the type of error. */
|
indicating the type of error. */
|
|
|
int ftp_get(char * hostname,
|
int ftp_get(char * hostname,
|
char * username,
|
char * username,
|
char * passwd,
|
char * passwd,
|
char * filename,
|
char * filename,
|
char * buf,
|
char * buf,
|
unsigned buf_size,
|
unsigned buf_size,
|
ftp_printf_t ftp_printf)
|
ftp_printf_t ftp_printf)
|
{
|
{
|
|
|
struct sockaddr_in local;
|
struct sockaddr_in local;
|
char msgbuf[256];
|
char msgbuf[256];
|
int s,data_s;
|
int s,data_s;
|
int bytes;
|
int bytes;
|
int ret;
|
int ret;
|
|
|
s = connect_to_server(hostname,&local,ftp_printf);
|
s = connect_to_server(hostname,&local,ftp_printf);
|
if (s < 0) {
|
if (s < 0) {
|
return (s);
|
return (s);
|
}
|
}
|
|
|
/* Read the welcome message from the server */
|
/* Read the welcome message from the server */
|
if (get_reply(s,ftp_printf) != 2) {
|
if (get_reply(s,ftp_printf) != 2) {
|
ftp_printf(0,"FTP: Server refused connection\n");
|
ftp_printf(0,"FTP: Server refused connection\n");
|
close(s);
|
close(s);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
ret = login(username,passwd,s,msgbuf,sizeof(msgbuf),ftp_printf);
|
ret = login(username,passwd,s,msgbuf,sizeof(msgbuf),ftp_printf);
|
if (ret < 0) {
|
if (ret < 0) {
|
close(s);
|
close(s);
|
return (ret);
|
return (ret);
|
}
|
}
|
|
|
/* We are now logged in and ready to transfer the file. Open the
|
/* We are now logged in and ready to transfer the file. Open the
|
data socket ready to receive the file. It also build the PORT
|
data socket ready to receive the file. It also build the PORT
|
command ready to send */
|
command ready to send */
|
data_s = opendatasock(s,local,msgbuf,sizeof(msgbuf),ftp_printf);
|
data_s = opendatasock(s,local,msgbuf,sizeof(msgbuf),ftp_printf);
|
if (data_s < 0) {
|
if (data_s < 0) {
|
close (s);
|
close (s);
|
return (data_s);
|
return (data_s);
|
}
|
}
|
|
|
/* Ask for the file */
|
/* Ask for the file */
|
ret = command("RETR",filename,s,msgbuf,sizeof(msgbuf),ftp_printf);
|
ret = command("RETR",filename,s,msgbuf,sizeof(msgbuf),ftp_printf);
|
if (ret < 0) {
|
if (ret < 0) {
|
close(s);
|
close(s);
|
close(data_s);
|
close(data_s);
|
return (ret);
|
return (ret);
|
}
|
}
|
|
|
if (ret != 1) {
|
if (ret != 1) {
|
ftp_printf(0,"FTP: RETR failed!\n");
|
ftp_printf(0,"FTP: RETR failed!\n");
|
close (data_s);
|
close (data_s);
|
close(s);
|
close(s);
|
return (FTP_BADFILENAME);
|
return (FTP_BADFILENAME);
|
}
|
}
|
|
|
if ((bytes=receive_file(data_s,buf,buf_size,ftp_printf)) < 0) {
|
if ((bytes=receive_file(data_s,buf,buf_size,ftp_printf)) < 0) {
|
ftp_printf(0,"FTP: Receiving file failed\n");
|
ftp_printf(0,"FTP: Receiving file failed\n");
|
close (data_s);
|
close (data_s);
|
close(s);
|
close(s);
|
return (bytes);
|
return (bytes);
|
}
|
}
|
|
|
if (get_reply(s,ftp_printf) != 2) {
|
if (get_reply(s,ftp_printf) != 2) {
|
ftp_printf(0,"FTP: Transfer failed!\n");
|
ftp_printf(0,"FTP: Transfer failed!\n");
|
close (data_s);
|
close (data_s);
|
close(s);
|
close(s);
|
return (FTP_BAD);
|
return (FTP_BAD);
|
}
|
}
|
|
|
ret = quit(s,msgbuf,sizeof(msgbuf),ftp_printf);
|
ret = quit(s,msgbuf,sizeof(msgbuf),ftp_printf);
|
if (ret < 0) {
|
if (ret < 0) {
|
close(s);
|
close(s);
|
close(data_s);
|
close(data_s);
|
return (ret);
|
return (ret);
|
}
|
}
|
|
|
close (data_s);
|
close (data_s);
|
close(s);
|
close(s);
|
return bytes;
|
return bytes;
|
}
|
}
|
|
|
/* Put a file on an FTP server. Hostname is the name/IP address of the
|
/* Put a file on an FTP server. Hostname is the name/IP address of the
|
server. username is the username used to connect to the server
|
server. username is the username used to connect to the server
|
with. Passwd is the password used to authentificate the
|
with. Passwd is the password used to authentificate the
|
username. filename is the name of the file to receive. It should be
|
username. filename is the name of the file to receive. It should be
|
the full pathname of the file. buf is a pointer to a buffer the
|
the full pathname of the file. buf is a pointer to a buffer the
|
contents of the file should be placed in and buf_size is the size
|
contents of the file should be placed in and buf_size is the size
|
of the buffer. ftp_printf is a function to be called to perform
|
of the buffer. ftp_printf is a function to be called to perform
|
printing. On success 0 is returned. On error a negative value is
|
printing. On success 0 is returned. On error a negative value is
|
returned indicating the type of error. */
|
returned indicating the type of error. */
|
|
|
int ftp_put(char * hostname,
|
int ftp_put(char * hostname,
|
char * username,
|
char * username,
|
char * passwd,
|
char * passwd,
|
char * filename,
|
char * filename,
|
char * buf,
|
char * buf,
|
unsigned buf_size,
|
unsigned buf_size,
|
ftp_printf_t ftp_printf)
|
ftp_printf_t ftp_printf)
|
{
|
{
|
|
|
struct sockaddr_in local;
|
struct sockaddr_in local;
|
char msgbuf[256];
|
char msgbuf[256];
|
int s,data_s;
|
int s,data_s;
|
int ret;
|
int ret;
|
|
|
s = connect_to_server(hostname,&local,ftp_printf);
|
s = connect_to_server(hostname,&local,ftp_printf);
|
if (s < 0) {
|
if (s < 0) {
|
return (s);
|
return (s);
|
}
|
}
|
|
|
/* Read the welcome message from the server */
|
/* Read the welcome message from the server */
|
if (get_reply(s,ftp_printf) != 2) {
|
if (get_reply(s,ftp_printf) != 2) {
|
ftp_printf(1,"FTP: Server refused connection\n");
|
ftp_printf(1,"FTP: Server refused connection\n");
|
close(s);
|
close(s);
|
return FTP_BAD;
|
return FTP_BAD;
|
}
|
}
|
|
|
ret = login(username,passwd,s,msgbuf,sizeof(msgbuf),ftp_printf);
|
ret = login(username,passwd,s,msgbuf,sizeof(msgbuf),ftp_printf);
|
if (ret < 0) {
|
if (ret < 0) {
|
close(s);
|
close(s);
|
return (ret);
|
return (ret);
|
}
|
}
|
|
|
/* We are now logged in and ready to transfer the file. Open the
|
/* We are now logged in and ready to transfer the file. Open the
|
data socket ready to receive the file. It also build the PORT
|
data socket ready to receive the file. It also build the PORT
|
command ready to send */
|
command ready to send */
|
data_s = opendatasock(s,local,msgbuf,sizeof(msgbuf),ftp_printf);
|
data_s = opendatasock(s,local,msgbuf,sizeof(msgbuf),ftp_printf);
|
if (data_s < 0) {
|
if (data_s < 0) {
|
close (s);
|
close (s);
|
return (data_s);
|
return (data_s);
|
}
|
}
|
|
|
/* Ask for the file */
|
/* Ask for the file */
|
ret = command("STOR",filename,s,msgbuf,sizeof(msgbuf),ftp_printf);
|
ret = command("STOR",filename,s,msgbuf,sizeof(msgbuf),ftp_printf);
|
if (ret < 0) {
|
if (ret < 0) {
|
close(s);
|
close(s);
|
close(data_s);
|
close(data_s);
|
return (ret);
|
return (ret);
|
}
|
}
|
|
|
if (ret != 1) {
|
if (ret != 1) {
|
ftp_printf(1,"FTP: STOR failed!\n");
|
ftp_printf(1,"FTP: STOR failed!\n");
|
close (data_s);
|
close (data_s);
|
close(s);
|
close(s);
|
return (FTP_BADFILENAME);
|
return (FTP_BADFILENAME);
|
}
|
}
|
|
|
if ((ret = send_file(data_s,buf,buf_size,ftp_printf)) < 0) {
|
if ((ret = send_file(data_s,buf,buf_size,ftp_printf)) < 0) {
|
ftp_printf(1,"FTP: Sending file failed\n");
|
ftp_printf(1,"FTP: Sending file failed\n");
|
close (data_s);
|
close (data_s);
|
close(s);
|
close(s);
|
return (ret);
|
return (ret);
|
}
|
}
|
|
|
if (get_reply(s,ftp_printf) != 2) {
|
if (get_reply(s,ftp_printf) != 2) {
|
ftp_printf(1,"FTP: Transfer failed!\n");
|
ftp_printf(1,"FTP: Transfer failed!\n");
|
close (data_s);
|
close (data_s);
|
close(s);
|
close(s);
|
return (FTP_BAD);
|
return (FTP_BAD);
|
}
|
}
|
|
|
ret = quit(s,msgbuf,sizeof(msgbuf),ftp_printf);
|
ret = quit(s,msgbuf,sizeof(msgbuf),ftp_printf);
|
if (ret < 0) {
|
if (ret < 0) {
|
close(s);
|
close(s);
|
close(data_s);
|
close(data_s);
|
return (ret);
|
return (ret);
|
}
|
}
|
|
|
close (data_s);
|
close (data_s);
|
close(s);
|
close(s);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* An example ftp_printf function. This uses the standard eCos diag
|
/* An example ftp_printf function. This uses the standard eCos diag
|
output device for outputting error and diagnostic messages. The
|
output device for outputting error and diagnostic messages. The
|
function take one addition parameter to the normal printf function. The
|
function take one addition parameter to the normal printf function. The
|
first parameter indicates when the message is an error message when
|
first parameter indicates when the message is an error message when
|
true. This can be used to filter errors from diagnostic output. In
|
true. This can be used to filter errors from diagnostic output. In
|
this example the error parameter is ignored and everything printed. */
|
this example the error parameter is ignored and everything printed. */
|
|
|
void ftpclient_printf(unsigned error, const char *fmt, ...)
|
void ftpclient_printf(unsigned error, const char *fmt, ...)
|
{
|
{
|
va_list ap;
|
va_list ap;
|
|
|
va_start(ap, fmt);
|
va_start(ap, fmt);
|
diag_vprintf( fmt, ap);
|
diag_vprintf( fmt, ap);
|
va_end(ap);
|
va_end(ap);
|
}
|
}
|
|
|