Mercurial > ecos
changeset 1004:c1abcb7d0cf8
* src/ftpclient.c (connect_to_server): Added support for
IPv6. This meant changing from using the PORT command to using
EPRT, when setting up the data connection. EPRT is protocol
independant.
* tests/ftpclient1.c (ftp_test): Added tests which use IPv6
addresses. Fixed a few minor bugs with format strings.
* doc/ftpclient.sgml: Mention we support IPv6 and DNS.
| author | asl |
|---|---|
| date | Mon, 12 May 2003 10:02:08 +0000 |
| parents | fae4fcdd86d2 |
| children | 1f968b35cd30 |
| files | packages/net/ftpclient/current/ChangeLog packages/net/ftpclient/current/doc/ftpclient.sgml packages/net/ftpclient/current/src/ftpclient.c packages/net/ftpclient/current/tests/ftpclient1.c |
| diffstat | 4 files changed, 146 insertions(+), 78 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/net/ftpclient/current/ChangeLog +++ b/packages/net/ftpclient/current/ChangeLog @@ -1,3 +1,13 @@ +2003-04-28 Andrew Lunn <andrew.lunn@ascom.ch> + + * src/ftpclient.c (connect_to_server): Added support for + IPv6. This meant changing from using the PORT command to using + EPRT, when setting up the data connection. EPRT is protocol + independant. + * tests/ftpclient1.c (ftp_test): Added tests which use IPv6 + addresses. Fixed a few minor bugs with format strings. + * doc/ftpclient.sgml: Mention we support IPv6 and DNS. + 2003-02-24 Jonathan Larmour <jifl@eCosCentric.com> * cdl/ftpclient.cdl: Add doc link. @@ -25,6 +35,7 @@ 2001-11-04 Andrew Lunn <andrew.lunn@as // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Andrew Lunn. // // 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
--- a/packages/net/ftpclient/current/doc/ftpclient.sgml +++ b/packages/net/ftpclient/current/doc/ftpclient.sgml @@ -11,6 +11,7 @@ <!-- --> <!-- =============================================================== --> <!-- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. --> +<!-- Copyright (C) 2003 Andrew Lunn. --> <!-- This material may be distributed only subject to the terms --> <!-- and conditions set forth in the Open Publication License, v1.0 --> <!-- or later (the latest version is presently available at --> @@ -34,7 +35,8 @@ <PARTINTRO> <PARA> The ftpclient package provides an FTP (File Transfer Protocol) client -for use with the TCP/IP stack in eCos. +for use with the TCP/IP stack in eCos. It supports both IPv4 and IPv6 +and will use the DNS client, when its is part of the eCos configuration. </PARA> </PARTINTRO> <CHAPTER id="net-ftpclient-features">
--- a/packages/net/ftpclient/current/src/ftpclient.c +++ b/packages/net/ftpclient/current/src/ftpclient.c @@ -209,66 +209,54 @@ command(char * cmd, static int connect_to_server(char *hostname, - struct sockaddr_in * local, + struct sockaddr * local, ftp_printf_t ftp_printf) { - struct sockaddr_in host; - struct servent *sent; -#ifdef CYGPKG_NS_DNS - struct hostent *hp=NULL; -#endif int s, len; + int error; + struct addrinfo *res, *nai; + char name[80]; + char port[8]; - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) { - ftp_printf(1,"socket: %s\n",strerror(errno)); - return FTP_BAD; - } - - sent = getservbyname("ftp", "tcp"); - if (sent == (struct servent *)0) { - ftp_printf(1,"FTP: unknown serivice\n"); - close(s); - return FTP_BAD; + error = getaddrinfo(hostname, "ftp", NULL, &res); + if (error != EAI_NONE) { + return FTP_NOSUCHHOST; } -#ifdef CYGPKG_NS_DNS - hp = gethostbyname(hostname); - - - if (hp) { /* try name first */ - host.sin_family = hp->h_addrtype; - bcopy(hp->h_addr, &host.sin_addr, hp->h_length); - } else -#endif - { /* maybe it's a numeric address ?*/ - host.sin_family = AF_INET; + nai=res; + while (nai) { + s = socket(nai->ai_family, nai->ai_socktype,nai->ai_protocol); + if (s < 0) { + nai = nai->ai_next; + continue; + } - if (inet_aton(hostname,&host.sin_addr) == 0) { - ftp_printf(1,"host not found: %s\n", hostname); + if (connect(s, nai->ai_addr, nai->ai_addrlen) < 0) { + getnameinfo(nai->ai_addr, nai->ai_addrlen, + name, sizeof(name), NULL,0, NI_NUMERICHOST); + ftp_printf(1,"FTP Connect to %s failed: %s\n",name, strerror(errno)); close (s); - return FTP_NOSUCHHOST; + nai = nai->ai_next; + continue; } + + len = sizeof(struct sockaddr); + if (getsockname(s, (struct sockaddr *)local, &len) < 0) { + ftp_printf(1,"getsockname failed %s\n",strerror(errno)); + close(s); + nai = nai->ai_next; + continue; + } + getnameinfo(nai->ai_addr, nai->ai_addrlen, + name, sizeof(name), port, sizeof(port), + NI_NUMERICHOST|NI_NUMERICSERV); + + ftp_printf(0,"FTP: Connected to %s:%s\n", name, port); + freeaddrinfo(res); + return (s); } - - host.sin_port = sent->s_port; - - if (connect(s, (struct sockaddr *)&host, sizeof(host)) < 0) { - ftp_printf(1,"FTP Connect failed: %s\n",strerror(errno)); - close (s); - return FTP_NOSUCHHOST; - } - - len = sizeof(struct sockaddr_in); - if (getsockname(s, (struct sockaddr *)local, &len) < 0) { - ftp_printf(1,"getsockname failed %s\n",strerror(errno)); - close(s); - return FTP_BAD; - } - ftp_printf(0,"FTP: Connected to %s.%d\n", - inet_ntoa(host.sin_addr), ntohs(host.sin_port)); - - return (s); + freeaddrinfo(res); + return FTP_NOSUCHHOST; } /* Perform a login to the server. Pass the username and password and @@ -320,20 +308,21 @@ opened send the port command to the serv port we are listening on.*/ static int opendatasock(int ctrl_s, - struct sockaddr_in ctrl, + struct sockaddr *ctrl, char *msgbuf, unsigned msgbuflen, ftp_printf_t ftp_printf) { - struct sockaddr_in local; + struct sockaddr local; + char name[64]; + char port[10]; socklen_t len; int on = 1; - char buf[4*6+1]; - char *a, *p; + char buf[80]; int ret; int s; - s = socket(AF_INET, SOCK_STREAM, 0); + s = socket(ctrl->sa_family, SOCK_STREAM, 0); if (s < 0) { ftp_printf(1,"socket: %s\n",strerror(errno)); return FTP_BAD; @@ -344,18 +333,34 @@ opendatasock(int ctrl_s, close(s); return FTP_BAD; } + + memcpy(&local,ctrl,sizeof(struct sockaddr)); + switch (ctrl->sa_family) { + case AF_INET: { + struct sockaddr_in * sa4 = (struct sockaddr_in *) &local; + sa4->sin_port = 0; + break; + } +#ifdef CYGPKG_NET_INET6 + case AF_INET6: { + struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *) &local; + sa6->sin6_port = 0; + break; + } +#endif + default: + close (s); + return FTP_BAD; + } - local = ctrl; - local.sin_family = AF_INET; - local.sin_port = 0; - if (bind(s,(struct sockaddr *)&local,sizeof(local)) < 0) { + if (bind(s,&local,local.sa_len) < 0) { ftp_printf(1,"bind: %s\n",strerror(errno)); close(s); return FTP_BAD; } len = sizeof(local); - if (getsockname(s,(struct sockaddr *)&local,&len) < 0) { + if (getsockname(s,&local,&len) < 0) { ftp_printf(1,"getsockname: %s\n",strerror(errno)); close(s); return FTP_BAD; @@ -366,15 +371,26 @@ opendatasock(int ctrl_s, close(s); return FTP_BAD; } + + getnameinfo(&local,sizeof(local),name,sizeof(name), port, sizeof(port), + NI_NUMERICHOST|NI_NUMERICSERV); + switch (local.sa_family) { + case AF_INET: { + sprintf(buf,"|1|%s|%s|", name, port); + break; + } +#ifdef CYGPKG_NET_INET6 + case AF_INET6: { + sprintf(buf,"|2|%s|%s|", name, port); + break; + } +#endif + default: + close (s); + return (FTP_BAD); + } -#define BtoI(b) (((int)b)&0xff) - a = (char *)&local.sin_addr; - p = (char *)&local.sin_port; - sprintf(buf,"%d,%d,%d,%d,%d,%d", - BtoI(a[0]),BtoI(a[1]),BtoI(a[2]),BtoI(a[3]), - BtoI(p[0]),BtoI(p[1])); - - ret = command("PORT",buf,ctrl_s,msgbuf,msgbuflen,ftp_printf); + ret = command("EPRT",buf,ctrl_s,msgbuf,msgbuflen,ftp_printf); if (ret < 0) { close(s); return (ret); @@ -511,7 +527,7 @@ int ftp_get(char * hostname, ftp_printf_t ftp_printf) { - struct sockaddr_in local; + struct sockaddr local; char msgbuf[256]; int s,data_s; int bytes; @@ -538,7 +554,7 @@ int ftp_get(char * hostname, /* 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 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) { close (s); return (data_s); @@ -604,7 +620,7 @@ int ftp_put(char * hostname, ftp_printf_t ftp_printf) { - struct sockaddr_in local; + struct sockaddr local; char msgbuf[256]; int s,data_s; int ret; @@ -630,7 +646,7 @@ int ftp_put(char * hostname, /* 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 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) { close (s); return (data_s);
--- a/packages/net/ftpclient/current/tests/ftpclient1.c +++ b/packages/net/ftpclient/current/tests/ftpclient1.c @@ -9,6 +9,7 @@ // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Andrew Lunn. // // 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 @@ -66,7 +67,7 @@ static cyg_handle_t thread_handle; #define __xstring(_x) __string(_x) #define _FTP_SRV __xstring(172.16.19.254) // farmnet dns0 address - +#define _FTP_SRV_V6 __xstring(fec0:0:0:2::1) #define FTPBUFSIZE (1024 * 64) char ftpbuf[FTPBUFSIZE]; char ftpbuf1[FTPBUFSIZE]; @@ -80,13 +81,13 @@ ftp_test(cyg_addrword_t p) init_all_network_interfaces(); - CYG_TEST_INFO("Getting /etc/passwd from %s\n" _FTP_SRV); + CYG_TEST_INFO("Getting /etc/passwd from " _FTP_SRV); ret = ftp_get(_FTP_SRV,"anonymous","ftpclient1", "/etc/passwd",ftpbuf,FTPBUFSIZE, ftpclient_printf); if (ret > 0) { - diag_printf("PASS:< %s bytes received>\n",ret); + diag_printf("PASS:< %d bytes received>\n",ret); } else { diag_printf("FAIL:< ftp_get returned %d>\n",ret); } @@ -108,13 +109,51 @@ ftp_test(cyg_addrword_t p) ftpclient_printf); if (ret > 0) { - diag_printf("PASS:< %s bytes received>\n",ret); + diag_printf("PASS:< %d bytes received>\n",ret); } else { diag_printf("FAIL:< ftp_get returned %d>\n",ret); } CYG_TEST_PASS_FAIL(!memcmp(ftpbuf,ftpbuf1,ret),"Transfer integrity"); +#ifdef CYGPKG_NET_INET6 + CYG_TEST_INFO("Getting /etc/passwd from " _FTP_SRV_V6); + ret = ftp_get(_FTP_SRV_V6,"anonymous","ftpclient1", + "/etc/passwd",ftpbuf,FTPBUFSIZE, + ftpclient_printf); + + if (ret > 0) { + diag_printf("PASS:< %d bytes received>\n",ret); + } else { + diag_printf("FAIL:< ftp_get returned %d>\n",ret); + } + + CYG_TEST_INFO("Putting passwd file back in /incoming/passwd\n"); + ret = ftp_put(_FTP_SRV_V6,"anonymous","ftpclient1", + "/incoming/passwd",ftpbuf,ret, + ftpclient_printf); + + if (ret > 0) { + diag_printf("PASS:\n"); + } else { + diag_printf("FAIL:< ftp_get returned %d>\n",ret); + } + + CYG_TEST_INFO("Reading back /incoming/passwd\n"); + ret = ftp_get(_FTP_SRV_V6,"anonymous","ftpclient1", + "/incoming/passwd",ftpbuf1,FTPBUFSIZE, + ftpclient_printf); + + if (ret > 0) { + diag_printf("PASS:< %d bytes received>\n",ret); + } else { + diag_printf("FAIL:< ftp_get returned %d>\n",ret); + } + + CYG_TEST_PASS_FAIL(!memcmp(ftpbuf,ftpbuf1,ret),"Transfer integrity"); + +#endif + CYG_TEST_INFO("ftp_Get'ing with a bad username\n"); ret = ftp_get(_FTP_SRV,"nosuchuser","ftpclient1", "/incoming/passwd",ftpbuf1,FTPBUFSIZE, @@ -140,7 +179,7 @@ ftp_test(cyg_addrword_t p) CYG_TEST_PASS_FAIL(ret==FTP_NOSUCHHOST,"Bad server"); CYG_TEST_INFO("ftp_get'ing a file which is too big"); - ret = ftp_get(_FTP_SRV,"nobody","ftpclient1", + ret = ftp_get(_FTP_SRV,"anonymous","ftpclient1", "/incoming/passwd",ftpbuf,2, ftpclient_printf); CYG_TEST_PASS_FAIL(ret==FTP_TOOBIG,"File too big");
