lavf/ftp: favour EPSV over PASV command
authorLukasz Marek <lukasz.m.luki2@gmail.com>
Mon, 19 May 2014 21:53:08 +0000 (23:53 +0200)
committerLukasz Marek <lukasz.m.luki2@gmail.com>
Mon, 19 May 2014 22:00:45 +0000 (00:00 +0200)
EPSV is newer version of PASV and allows to use IPv6.

Signed-off-by: Lukasz Marek <lukasz.m.luki2@gmail.com>
libavformat/ftp.c

index dae8aa0..6001165 100644 (file)
@@ -227,6 +227,48 @@ static int ftp_auth(FTPContext *s)
     return 0;
 }
 
+static int ftp_passive_mode_epsv(FTPContext *s)
+{
+    char *res = NULL, *start = NULL, *end = NULL;
+    int i;
+    static const char d = '|';
+    static const char *command = "EPSV\r\n";
+    static const int epsv_codes[] = {229, 500, 501, 0}; /* 500, 501 are incorrect codes */
+
+    if (ftp_send_command(s, command, epsv_codes, &res) != 229 || !res)
+        goto fail;
+
+    for (i = 0; res[i]; ++i) {
+        if (res[i] == '(') {
+            start = res + i + 1;
+        } else if (res[i] == ')') {
+            end = res + i;
+            break;
+        }
+    }
+    if (!start || !end)
+        goto fail;
+
+    *end = '\0';
+    if (strlen(start) < 5)
+        goto fail;
+    if (start[0] != d || start[1] != d || start[2] != d || end[-1] != d)
+        goto fail;
+    start += 3;
+    end[-1] = '\0';
+
+    s->server_data_port = atoi(start);
+    av_dlog(s, "Server data port: %d\n", s->server_data_port);
+
+    av_free(res);
+    return 0;
+
+  fail:
+    av_free(res);
+    s->server_data_port = -1;
+    return AVERROR(ENOSYS);
+}
+
 static int ftp_passive_mode(FTPContext *s)
 {
     char *res = NULL, *start = NULL, *end = NULL;
@@ -270,8 +312,6 @@ static int ftp_passive_mode(FTPContext *s)
   fail:
     av_free(res);
     s->server_data_port = -1;
-    av_log(s, AV_LOG_ERROR, "Set passive mode failed\n"
-                            "Your FTP server may use IPv6 which is not supported yet.\n");
     return AVERROR(EIO);
 }
 
@@ -439,8 +479,11 @@ static int ftp_connect_data_connection(URLContext *h)
 
     if (!s->conn_data) {
         /* Enter passive mode */
-        if ((err = ftp_passive_mode(s)) < 0)
-            return err;
+        if (ftp_passive_mode_epsv(s) < 0) {
+            /* Use PASV as fallback */
+            if ((err = ftp_passive_mode(s)) < 0)
+                return err;
+        }
         /* Open data connection */
         ff_url_join(buf, sizeof(buf), "tcp", NULL, s->hostname, s->server_data_port, NULL);
         if (s->rw_timeout != -1) {