From b9419b58826effc3d9afabd1a2e50d66391fbdbf Mon Sep 17 00:00:00 2001 From: Lukasz Marek Date: Mon, 19 May 2014 23:53:08 +0200 Subject: [PATCH] lavf/ftp: favour EPSV over PASV command EPSV is newer version of PASV and allows to use IPv6. Signed-off-by: Lukasz Marek --- libavformat/ftp.c | 51 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/libavformat/ftp.c b/libavformat/ftp.c index dae8aa086d..60011650b5 100644 --- a/libavformat/ftp.c +++ b/libavformat/ftp.c @@ -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) {