]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/ftp.c
Merge commit '6d212599aa684f30511fb08ca30fe2378405304e'
[ffmpeg] / libavformat / ftp.c
index dae8aa086d2f45ede2cea0b81694c04351cda14b..60011650b5f5a2f8cba827619670ec3ec2c501fc 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) {