[FFmpeg-devel] [PATCH 3/3] lavf/ftp: support credentials callback
Lukasz Marek
lukasz.m.luki2 at gmail.com
Wed Apr 8 01:04:58 CEST 2015
---
libavformat/ftp.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 83 insertions(+), 13 deletions(-)
diff --git a/libavformat/ftp.c b/libavformat/ftp.c
index 27a172e..1133e02 100644
--- a/libavformat/ftp.c
+++ b/libavformat/ftp.c
@@ -74,6 +74,36 @@ static const AVClass ftp_context_class = {
static int ftp_close(URLContext *h);
+static int ftp_get_password(URLContext *h)
+{
+ FTPContext *s = h->priv_data;
+ int ret;
+ AVIOCredentials cretentials = {
+ .username = av_strdup(av_x_if_null(s->user, "anonymous")),
+ .password = av_strdup(av_x_if_null(s->password, "")),
+ };
+
+ if (!cretentials.username || !cretentials.password) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if ((ret = ff_url_get_credentials(h, &cretentials)) < 0)
+ goto fail;
+
+ av_free(s->user);
+ av_free(s->password);
+ s->user = cretentials.username;
+ s->password = cretentials.password;
+
+ return 0;
+
+ fail:
+ av_free(cretentials.username);
+ av_free(cretentials.password);
+ return ret;
+}
+
static int ftp_getc(FTPContext *s)
{
int len;
@@ -82,7 +112,7 @@ static int ftp_getc(FTPContext *s)
if (len < 0) {
return len;
} else if (!len) {
- return -1;
+ return AVERROR(EPIPE);
} else {
s->control_buf_ptr = s->control_buffer;
s->control_buf_end = s->control_buffer + len;
@@ -191,7 +221,7 @@ static int ftp_send_command(FTPContext *s, const char *command,
if ((err = ffurl_write(s->conn_control, command, strlen(command))) < 0)
return err;
if (!err)
- return -1;
+ return AVERROR(EPIPE);
/* return status */
if (response_codes) {
@@ -213,12 +243,13 @@ static void ftp_close_both_connections(FTPContext *s)
ftp_close_data_connection(s);
}
-static int ftp_auth(FTPContext *s)
+static int ftp_auth(URLContext *h)
{
+ FTPContext *s = h->priv_data;
char buf[CONTROL_BUFFER_SIZE];
int err;
- static const int user_codes[] = {331, 230, 0};
- static const int pass_codes[] = {230, 0};
+ static const int user_codes[] = {421, 331, 230, 0};
+ static const int pass_codes[] = {421, 230, 0};
snprintf(buf, sizeof(buf), "USER %s\r\n", s->user);
err = ftp_send_command(s, buf, user_codes, NULL);
@@ -229,6 +260,10 @@ static int ftp_auth(FTPContext *s)
} else
return AVERROR(EACCES);
}
+ if (err < 0)
+ return err;
+ if (err == 421)
+ return AVERROR(EPIPE);
if (err != 230)
return AVERROR(EACCES);
@@ -434,6 +469,17 @@ static int ftp_restart(FTPContext *s, int64_t pos)
return 0;
}
+static int ftp_noop(FTPContext *s)
+{
+ static const char *command = "TYPE I\r\n";
+ static const int noop_codes[] = {200, 0};
+
+ if (ftp_send_command(s, command, noop_codes, NULL) != 200)
+ return AVERROR(EIO);
+
+ return 0;
+}
+
static int ftp_features(FTPContext *s)
{
static const char *feat_command = "FEAT\r\n";
@@ -459,6 +505,11 @@ static int ftp_connect_control_connection(URLContext *h)
FTPContext *s = h->priv_data;
static const int connect_codes[] = {220, 0};
+ if (s->conn_control) {
+ /* check if connection is alive */
+ if (ftp_noop(s) < 0)
+ ftp_close_both_connections(s);
+ }
if (!s->conn_control) {
ff_url_join(buf, sizeof(buf), "tcp", NULL,
s->hostname, s->server_control_port, NULL);
@@ -484,10 +535,21 @@ static int ftp_connect_control_connection(URLContext *h)
}
av_free(response);
- if ((err = ftp_auth(s)) < 0) {
- av_log(h, AV_LOG_ERROR, "FTP authentication failed\n");
- return err;
- }
+ do {
+ err = ftp_auth(h);
+ if (err >= 0)
+ break;
+ if (err < 0 && err != AVERROR(EACCES)) {
+ if (err != AVERROR(EPIPE))
+ av_log(h, AV_LOG_ERROR, "FTP authentication failed\n");
+ return err;
+ }
+ if ((err = ftp_get_password(h)) < 0) {
+ if (err == AVERROR(ENOSYS))
+ err = AVERROR(EACCES);
+ return err;
+ }
+ } while (1);
if ((err = ftp_type(s)) < 0) {
av_log(h, AV_LOG_ERROR, "Set content type failed\n");
@@ -575,7 +637,7 @@ static int ftp_open(URLContext *h, const char *url, int flags)
char proto[10], path[MAX_URL_SIZE], credencials[MAX_URL_SIZE], hostname[MAX_URL_SIZE];
const char *tok_user = NULL, *tok_pass = NULL;
char *end = NULL;
- int err;
+ int err, retry = 100;
size_t pathlen;
FTPContext *s = h->priv_data;
@@ -596,7 +658,7 @@ static int ftp_open(URLContext *h, const char *url, int flags)
tok_pass = av_strtok(end, ":", &end);
if (!tok_user) {
tok_user = "anonymous";
- tok_pass = av_x_if_null(s->anonymous_password, "nopassword");
+ tok_pass = s->anonymous_password;
}
s->user = av_strdup(tok_user);
s->password = av_strdup(tok_pass);
@@ -609,8 +671,16 @@ static int ftp_open(URLContext *h, const char *url, int flags)
if (s->server_control_port < 0 || s->server_control_port > 65535)
s->server_control_port = 21;
- if ((err = ftp_connect_control_connection(h)) < 0)
- goto fail;
+ do {
+ err = ftp_connect_control_connection(h);
+ if (err >= 0)
+ break;
+ if (err < 0) {
+ if (err == AVERROR(EPIPE))
+ continue;
+ goto fail;
+ }
+ } while(retry--);
if ((err = ftp_current_dir(s)) < 0)
goto fail;
--
1.9.1
More information about the ffmpeg-devel
mailing list