rpms/mc/devel mc-ipv6.patch,NONE,1.1 mc.spec,1.103,1.104

fedora-cvs-commits at redhat.com fedora-cvs-commits at redhat.com
Tue Sep 26 08:47:35 UTC 2006


Author: jnovy

Update of /cvs/dist/rpms/mc/devel
In directory cvs.devel.redhat.com:/tmp/cvs-serv12175

Modified Files:
	mc.spec 
Added Files:
	mc-ipv6.patch 
Log Message:
- add experimental IPv6 support for ftpfs (#198386)


mc-ipv6.patch:
 ftpfs.c |  300 +++++++++++++++++++++++++++++++++++++++++++---------------------
 ftpfs.h |    3 
 2 files changed, 207 insertions(+), 96 deletions(-)

--- NEW FILE mc-ipv6.patch ---
--- mc-2006-09-12-21/vfs/ftpfs.c.ipv6	2006-03-08 16:17:55.000000000 +0100
+++ mc-2006-09-12-21/vfs/ftpfs.c	2006-09-26 10:43:27.000000000 +0200
@@ -639,12 +639,13 @@ ftpfs_get_proxy_host_and_port (const cha
 static int
 ftpfs_open_socket (struct vfs_class *me, struct vfs_s_super *super)
 {
-    struct   sockaddr_in server_address;
-    struct   hostent *hp;
-    int      my_socket;
+    struct addrinfo hints, *res, *restmp;
+    int      my_socket = 0;
     char     *host;
-    int      port = SUP.port;
+    char     *port;
+    int      tmp_port;
     int      free_host = 0;
+    int      e;
 
     (void) me;
     
@@ -657,62 +658,83 @@ ftpfs_open_socket (struct vfs_class *me,
 	return -1;
     }
 
+    port = malloc (sizeof (char) * 6);
+    if (port == NULL) {
+      ftpfs_errno = errno;
+      return -1;
+    }
+
     /* Hosts to connect to that start with a ! should use proxy */
+    tmp_port = SUP.port;
+
     if (SUP.proxy){
-	ftpfs_get_proxy_host_and_port (ftpfs_proxy_host, &host, &port);
+	ftpfs_get_proxy_host_and_port (ftpfs_proxy_host, &host, &tmp_port);
 	free_host = 1;
     }
 
-    enable_interrupt_key(); /* clear the interrupt flag */
-    
-    /* Get host address */
-    memset ((char *) &server_address, 0, sizeof (server_address));
-    server_address.sin_family = AF_INET;
-    server_address.sin_addr.s_addr = inet_addr (host);
-    if (server_address.sin_addr.s_addr == INADDR_NONE) {
-	hp = gethostbyname (host);
-	if (hp == NULL){
-	    disable_interrupt_key();
-	    print_vfs_message (_("ftpfs: Invalid host address."));
-	    ftpfs_errno = EINVAL;
-	    if (free_host)
-		g_free (host);
-	    return -1;
-	}
-	server_address.sin_family = hp->h_addrtype;
-
-	/* We copy only 4 bytes, we cannot trust hp->h_length, as it comes from the DNS */
-	memcpy ((char *) &server_address.sin_addr, (char *) hp->h_addr, 4);
+    if (snprintf (port, 6, "%hu", (unsigned short)tmp_port) < 0) {
+      g_free (port);
+      if (free_host)
+	g_free (host);
+      ftpfs_errno = errno;
+      return -1;
     }
 
-    server_address.sin_port = htons (port);
+    enable_interrupt_key(); /* clear the interrupt flag */
 
-    /* Connect */
-    if ((my_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
-	disable_interrupt_key();
-	ftpfs_errno = errno;
-        if (free_host)
-	    g_free (host);
-	return -1;
-    }
-    
-    print_vfs_message (_("ftpfs: making connection to %s"), host);
-    if (free_host)
+    memset (&hints, 0, sizeof (struct addrinfo));
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_ADDRCONFIG;
+
+    if ((e = getaddrinfo (host, port, &hints, &res)) != 0) {
+      disable_interrupt_key();
+      print_vfs_message (_("ftpfs: %s"), gai_strerror (e));
+      if (free_host)
 	g_free (host);
-
-    if (connect (my_socket, (struct sockaddr *) &server_address,
-	     sizeof (server_address)) < 0){
-	ftpfs_errno = errno;
-	if (errno == EINTR && got_interrupt ())
+      g_free (port);
+      ftpfs_errno = EINVAL;
+      return -1;
+    }
+    g_free (port);
+
+    for (restmp = res; res != NULL; res = res->ai_next) {
+      my_socket = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
+      if (my_socket < 0) {
+	if (res->ai_next == NULL) {
+	  disable_interrupt_key();
+	  print_vfs_message (_("ftpfs: %s"), unix_error_string (errno));
+	  if (free_host)
+	    g_free (host);
+	  freeaddrinfo (restmp);
+	  ftpfs_errno = errno;
+	  return -1;
+	} else
+	  continue;
+      } else {
+	print_vfs_message (_("ftpfs: making connection to %s"), host);
+	if (free_host)
+	  g_free (host);
+	
+	if (connect (my_socket, res->ai_addr, res->ai_addrlen) < 0) {
+	  ftpfs_errno = errno;
+	  close (my_socket);
+	  if (errno == EINTR && got_interrupt ()) {
 	    print_vfs_message (_("ftpfs: connection interrupted by user"));
-	else
+	  } else if (res->ai_next == NULL) {
 	    print_vfs_message (_("ftpfs: connection to server failed: %s"),
-				   unix_error_string(errno));
-	disable_interrupt_key();
-	close (my_socket);
-	return -1;
+			       unix_error_string (errno));
+	  } else
+	    continue;
+	  freeaddrinfo (restmp);
+	  disable_interrupt_key ();
+	  return -1;
+	} else
+	  break;
+      }
     }
-    disable_interrupt_key();
+
+    freeaddrinfo (restmp);
+    disable_interrupt_key ();
     return my_socket;
 }
 
@@ -861,93 +883,179 @@ ftpfs_get_current_directory (struct vfs_
     
 /* Setup Passive ftp connection, we use it for source routed connections */
 static int
-ftpfs_setup_passive (struct vfs_class *me, struct vfs_s_super *super, int my_socket, struct sockaddr_in *sa)
+ftpfs_setup_passive (struct vfs_class *me, struct vfs_s_super *super, int my_socket, struct sockaddr_storage *sa, socklen_t *salen)
 {
+  char *c;
+  
+  if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "EPSV") == COMPLETE) {
+    int port;
+    /* (|||<port>|) */
+    c = strchr (reply_str, '|');
+    if (c == NULL)
+      return 0;
+    if(strlen(c) > 3)
+      c+=3;
+    else
+      return 0;
+
+    port = atoi (c);
+    if (port < 0 || port > 65535)
+      return 0;
+    port = htons (port);
+
+    switch (sa->ss_family) {
+    case AF_INET:
+      ((struct sockaddr_in *)sa)->sin_port = port;
+      break;
+    case AF_INET6:
+      ((struct sockaddr_in6 *)sa)->sin6_port = port;
+      break;
+    default:
+      print_vfs_message (_("ftpfs: invalid address family"));
+      ERRNOR (EINVAL, -1);
+    }
+  } else if (sa->ss_family == AF_INET) {
     int xa, xb, xc, xd, xe, xf;
     char n [6];
-    char *c;
     
     if (ftpfs_command (me, super, WAIT_REPLY | WANT_STRING, "PASV") != COMPLETE)
-	return 0;
-
+      return 0;
+    
     /* Parse remote parameters */
     for (c = reply_str + 4; (*c) && (!isdigit ((unsigned char) *c)); c++)
-	;
+      ;
     if (!*c)
-	return 0;
+      return 0;
     if (!isdigit ((unsigned char) *c))
-	return 0;
+      return 0;
     if (sscanf (c, "%d,%d,%d,%d,%d,%d", &xa, &xb, &xc, &xd, &xe, &xf) != 6)
-	return 0;
+      return 0;
     n [0] = (unsigned char) xa;
     n [1] = (unsigned char) xb;
     n [2] = (unsigned char) xc;
     n [3] = (unsigned char) xd;
     n [4] = (unsigned char) xe;
     n [5] = (unsigned char) xf;
+    
+    memcpy (&(((struct sockaddr_in *)sa)->sin_addr.s_addr), (void *)n, 4);
+    memcpy (&(((struct sockaddr_in *)sa)->sin_port), (void *)&n[4], 2);
+  } else
+    return 0;
 
-    memcpy (&(sa->sin_addr.s_addr), (void *)n, 4);
-    memcpy (&(sa->sin_port), (void *)&n[4], 2);
-    if (connect (my_socket, (struct sockaddr *) sa, sizeof (struct sockaddr_in)) < 0)
-	return 0;
-    return 1;
+  if (connect (my_socket, (struct sockaddr *) sa, *salen ) < 0)
+    return 0;
+
+  return 1;
 }
 
 static int
 ftpfs_initconn (struct vfs_class *me, struct vfs_s_super *super)
 {
-    struct sockaddr_in data_addr;
-    int data;
-    socklen_t len = sizeof(data_addr);
-    struct protoent *pe;
+  struct sockaddr_storage data_addr;
+  socklen_t data_addrlen;
+  int data_sock;
 
-    pe = getprotobyname ("tcp");
-    if (pe == NULL)
-	ERRNOR (EIO, -1);
 again:
-    if (getsockname (SUP.sock, (struct sockaddr *) &data_addr, &len) == -1)
-	ERRNOR (EIO, -1);
-    data_addr.sin_port = 0;
-    
-    data = socket (AF_INET, SOCK_STREAM, pe->p_proto);
-    if (data < 0)
-	ERRNOR (EIO, -1);
+  memset (&data_addr, 0, sizeof (struct sockaddr_storage));
+  data_addrlen = sizeof (struct sockaddr_storage);
 
-    if (SUP.use_passive_connection) {
-	if (ftpfs_setup_passive (me, super, data, &data_addr))
-	    return data;
-
-	SUP.use_passive_connection = 0;
-	print_vfs_message (_("ftpfs: could not setup passive mode"));
+  if (getsockname (SUP.sock, (struct sockaddr *) &data_addr, &data_addrlen) == -1)
+    return -1;
+  
+  switch (data_addr.ss_family) {
+  case AF_INET:
+    ((struct sockaddr_in *)&data_addr)->sin_port = 0;
+    break;
+  case AF_INET6:
+    ((struct sockaddr_in6 *)&data_addr)->sin6_port = 0;
+    break;
+  default:
+    print_vfs_message (_("ftpfs: invalid address family"));
+    ERRNOR(EINVAL, -1);
+  }
 
-	/* data or data_addr may be damaged by ftpfs_setup_passive */
-	close (data);
-	goto again;
+  data_sock = socket (data_addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
+  if (data_sock < 0) {
+    if (SUP.use_passive_connection) {
+      print_vfs_message (_("ftpfs: could not setup passive mode: %s"), unix_error_string (errno));
+      SUP.use_passive_connection = 0;
+      goto again;
     }
+    print_vfs_message (_("ftpfs: could not create socket: %s"), unix_error_string (errno));
+    return -1;
+  }
 
+  if (SUP.use_passive_connection) {
+    if (ftpfs_setup_passive (me, super, data_sock, &data_addr, &data_addrlen))
+      return data_sock;
+
+    SUP.use_passive_connection = 0;
+    print_vfs_message (_("ftpfs: could not setup passive mode"));
+
+    close (data_sock);
+    goto again;
+  }
+  
     /* If passive setup fails, fallback to active connections */
     /* Active FTP connection */
-    if ((bind (data, (struct sockaddr *)&data_addr, len) == 0) &&
-	(getsockname (data, (struct sockaddr *) &data_addr, &len) == 0) && 
-	(listen (data, 1) == 0))
+  if ((bind (data_sock, (struct sockaddr *)&data_addr, data_addrlen) == 0) &&
+      (getsockname (data_sock, (struct sockaddr *)&data_addr, &data_addrlen) == 0) && 
+      (listen (data_sock, 1) == 0))
     {
-	unsigned char *a = (unsigned char *)&data_addr.sin_addr;
-	unsigned char *p = (unsigned char *)&data_addr.sin_port;
+      unsigned short int port;
+      char *addr;
+      unsigned int af;
+
+      switch (data_addr.ss_family) {
+      case AF_INET: 
+	af = FTP_INET;
+	port = ((struct sockaddr_in *)&data_addr)->sin_port;
+	break;
+      case AF_INET6: 
+	af = FTP_INET6;
+	port = ((struct sockaddr_in6 *)&data_addr)->sin6_port;
+	break;
+      default:
+	print_vfs_message (_("ftpfs: invalid address family"));
+	ERRNOR (EINVAL, -1);
+      }
+      port = ntohs (port);
+     
+      addr = malloc (NI_MAXHOST);
+      if (addr == NULL)
+	ERRNOR (ENOMEM, -1);
+
+      if (getnameinfo ((struct sockaddr *)&data_addr, data_addrlen, addr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) {
+	g_free (addr);
+	ERRNOR (EIO, -1);
+      }
+
+      if (ftpfs_command (me, super, WAIT_REPLY, "EPRT |%u|%s|%hu|", af, addr, port) == COMPLETE) {
+	g_free (addr);
+	return data_sock;
+      }
+      g_free (addr);
+      
+      if (FTP_INET == af) {
+	unsigned char *a = (unsigned char *)&((struct sockaddr_in *)&data_addr)->sin_addr;
+	unsigned char *p = (unsigned char *)&port;
 	
-	if (ftpfs_command (me, super, WAIT_REPLY, "PORT %d,%d,%d,%d,%d,%d", a[0], a[1], 
-		     a[2], a[3], p[0], p[1]) == COMPLETE)
-	    return data;
+	if (ftpfs_command (me, super, WAIT_REPLY, "PORT %u,%u,%u,%u,%u,%u", a[0], a[1], a[2], a[3],
+			   p[0], p[1]) == COMPLETE)
+	  return data_sock;
+      }
     }
-    close (data);
-    ftpfs_errno = EIO;
-    return -1;
+
+  close (data_sock);
+  ftpfs_errno = EIO;
+  return -1;
 }
 
 static int
 ftpfs_open_data_connection (struct vfs_class *me, struct vfs_s_super *super, const char *cmd,
 		      const char *remote, int isbinary, int reget)
 {
-    struct sockaddr_in from;
+    struct sockaddr_storage from;
     int s, j, data;
     socklen_t fromlen = sizeof(from);
     
--- mc-2006-09-12-21/vfs/ftpfs.h.ipv6	2005-05-29 14:10:08.000000000 +0200
+++ mc-2006-09-12-21/vfs/ftpfs.h	2006-09-26 10:42:36.000000000 +0200
@@ -15,6 +15,9 @@ extern int ftpfs_first_cd_then_ls;
 void ftpfs_init_passwd (void);
 void init_ftpfs (void);
 
+#define FTP_INET  1
+#define FTP_INET6 2
+
 #define OPT_FLUSH        1
 #define OPT_IGNORE_ERROR 2
 


Index: mc.spec
===================================================================
RCS file: /cvs/dist/rpms/mc/devel/mc.spec,v
retrieving revision 1.103
retrieving revision 1.104
diff -u -r1.103 -r1.104
--- mc.spec	13 Sep 2006 07:56:27 -0000	1.103
+++ mc.spec	26 Sep 2006 08:47:33 -0000	1.104
@@ -3,7 +3,7 @@
 Summary:	User-friendly text console file manager and visual shell
 Name:		mc
 Version:	4.6.1a
-Release:	28%{?dist}
+Release:	29%{?dist}
 Epoch:		1
 License:	GPL
 Group:		System Environment/Shells
@@ -27,6 +27,7 @@
 Patch12:	mc-exit.patch
 Patch13:	mc-fishfix.patch
 Patch14:	mc-utf8-8bit-hex.patch
+Patch15:	mc-ipv6.patch
 
 %description
 Midnight Commander is a visual shell much like a file manager, only
@@ -52,6 +53,7 @@
 %patch12 -p1 -b .exit
 %patch13 -p1 -b .fishfix
 %patch14 -p1 -b .8bit-hex
+%patch15 -p1 -b .ipv6
 
 # convert files in /lib to UTF-8
 pushd lib
@@ -196,6 +198,10 @@
 %dir %{_sysconfdir}/mc
 
 %changelog
+* Tue Sep 26 2006 Jindrich Novy <jnovy at redhat.com> 4.6.1a-29
+- add experimental IPv6 support for ftpfs (#198386), thanks to
+  Dan Kopecek for the patch
+
 * Wed Sep 13 2006 Jindrich Novy <jnovy at redhat.com> 4.6.1a-28.fc6
 - update to new CVS snapshot (09-12-21)
 - drop .assembly, .spec patches -> applied upstream




More information about the fedora-cvs-commits mailing list