]> git.sesse.net Git - vlc/commitdiff
Implement Extended passive mode
authorRémi Denis-Courmont <rem@videolan.org>
Sat, 21 May 2005 18:59:49 +0000 (18:59 +0000)
committerRémi Denis-Courmont <rem@videolan.org>
Sat, 21 May 2005 18:59:49 +0000 (18:59 +0000)
(RFC2428 - FTP Extensions for IPv6 and NATs) :
- explicitly NAT-friendly FTP (refs #66),
- IPv6 support (closes #130).

modules/access/ftp.c

index 4194a2ae3e4a186a0c22e5ca65d99df956fadbeb..bb4befa3674d232411b26d7bdf91d1f0e79260bb 100644 (file)
@@ -78,10 +78,12 @@ static int Control( access_t *, int, va_list );
 
 struct access_sys_t
 {
-    vlc_url_t url;
+    vlc_url_t  url;
 
-    int       fd_cmd;
-    int       fd_data;
+    int        fd_cmd;
+    int        fd_data;
+    
+    vlc_bool_t b_epsv;
 };
 
 static int  ftp_SendCommand( access_t *, char *, ... );
@@ -220,6 +222,20 @@ static int Open( vlc_object_t *p_this )
             goto exit_error;
     }
 
+    /* Extended passive mode */
+    if( ftp_SendCommand( p_access, "EPSV ALL" ) < 0 )
+    {
+        msg_Err( p_access, "cannot request extended passive mode" );
+        goto exit_error;
+    }
+    if( ftp_ReadCommand( p_access, &i_answer, NULL ) != 2 )
+    {
+        p_sys->b_epsv = VLC_FALSE;
+        msg_Warn( p_access, "Extended passive mode not supported" );
+    }
+    else
+        p_sys->b_epsv = VLC_TRUE;
+
     /* binary mode */
     if( ftp_SendCommand( p_access, "TYPE I" ) < 0 ||
         ftp_ReadCommand( p_access, &i_answer, NULL ) != 2 )
@@ -401,7 +417,6 @@ static int ftp_SendCommand( access_t *p_access, char *psz_fmt, ... )
     access_sys_t *p_sys = p_access->p_sys;
     va_list      args;
     char         *psz_cmd;
-    int          i_ret;
 
     va_start( args, psz_fmt );
     vasprintf( &psz_cmd, psz_fmt, args );
@@ -491,33 +506,61 @@ static int ftp_StartStream( access_t *p_access, off_t i_start )
 {
     access_sys_t *p_sys = p_access->p_sys;
 
-    char psz_ip[1000];
+    char psz_ipv4[16], *psz_ip;
     int  i_answer;
     char *psz_arg, *psz_parser;
-    int  a1,a2,a3,a4;
-    int  p1,p2;
+    unsigned  a1, a2, a3, a4, p1, p2;
     int  i_port;
 
-    if( ftp_SendCommand( p_access, "PASV" ) < 0 ||
-        ftp_ReadCommand( p_access, &i_answer, &psz_arg ) != 2 )
+    if( ( ftp_SendCommand( p_access, p_sys->b_epsv ? "EPSV" : "PASV" ) < 0 )
+     || ( ftp_ReadCommand( p_access, &i_answer, &psz_arg ) != 2 ) )
     {
-        msg_Err( p_access, "cannot set passive transfer mode" );
+        msg_Err( p_access, "cannot set passive mode" );
         return VLC_EGENERIC;
     }
 
     psz_parser = strchr( psz_arg, '(' );
-    if( !psz_parser ||
-        sscanf( psz_parser, "(%d,%d,%d,%d,%d,%d", &a1, &a2, &a3,
-                &a4, &p1, &p2 ) < 6 )
+    if( psz_parser == NULL )
     {
         free( psz_arg );
-        msg_Err( p_access, "cannot get ip/port for passive transfer mode" );
+        msg_Err( p_access, "cannot parse passive mode response" );
         return VLC_EGENERIC;
     }
+
+    if( p_sys->b_epsv )
+    {
+        char psz_fmt[7] = "(|||%u";
+        psz_fmt[1] = psz_fmt[2] = psz_fmt[3] = psz_parser[1];
+
+        if( sscanf( psz_parser, psz_fmt, &i_port ) < 1 )
+        {
+            free( psz_arg );
+            msg_Err( p_access, "cannot parse passive mode response" );
+            return VLC_EGENERIC;
+        }
+        /* FIXME: if psz_ip is a hostname/DNS to a cluster of FTP servers,
+         * this may fail because we'll end up on another server :(
+         * getpeername() + getnameinfo() should be used instead.
+         */
+        psz_ip = p_sys->url.psz_host;
+    }
+    else
+    {
+        if( ( sscanf( psz_parser, "(%u,%u,%u,%u,%u,%u", &a1, &a2, &a3, &a4,
+                      &p1, &p2 ) < 6 ) || ( a1 > 255 ) || ( a2 > 255 )
+         || ( a3 > 255 ) || ( a4 > 255 ) || ( p1 > 255 ) || ( p2 > 255 ) )
+        {
+            free( psz_arg );
+            msg_Err( p_access, "cannot parse passive mode response" );
+            return VLC_EGENERIC;
+        }
+
+        sprintf( psz_ipv4, "%u.%u.%u.%u", a1, a2, a3, a4 );
+        psz_ip = psz_ipv4;
+        i_port = (p1 << 8) | p2;
+    }
     free( psz_arg );
 
-    sprintf( psz_ip, "%d.%d.%d.%d", a1, a2, a3, a4 );
-    i_port = p1 * 256 + p2;
     msg_Dbg( p_access, "ip:%s port:%d", psz_ip, i_port );
 
     if( ftp_SendCommand( p_access, "TYPE I" ) < 0 ||