diff packages/net/ftpclient/current/src/ftpclient.c @ 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 7fffb214536c
children 353800bc5758
line wrap: on
line diff
--- 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);