Commit 4d617715 authored by Lukasz Marek's avatar Lukasz Marek

ftp: abort function optimalization

It seems some ftp servers doesn't respect ABOR command,
but closing both connection is slow.

This commit keeps control connection open when possible.
Signed-off-by: 's avatarLukasz Marek <lukasz.m.luki@gmail.com>
parent bc29acdc
...@@ -172,9 +172,6 @@ static int ftp_status(FTPContext *s, char **line, const int response_codes[]) ...@@ -172,9 +172,6 @@ static int ftp_status(FTPContext *s, char **line, const int response_codes[])
return result; return result;
} }
/* first code received. Now get all lines in non blocking mode */
s->conn_control_block_flag = 1;
av_log(s, AV_LOG_DEBUG, "%s\n", buf); av_log(s, AV_LOG_DEBUG, "%s\n", buf);
if (!pref_code_found) { if (!pref_code_found) {
...@@ -191,6 +188,8 @@ static int ftp_status(FTPContext *s, char **line, const int response_codes[]) ...@@ -191,6 +188,8 @@ static int ftp_status(FTPContext *s, char **line, const int response_codes[])
for (i = 0; response_codes[i]; ++i) { for (i = 0; response_codes[i]; ++i) {
if (err == response_codes[i]) { if (err == response_codes[i]) {
/* first code received. Now get all lines in non blocking mode */
s->conn_control_block_flag = 1;
pref_code_found = 1; pref_code_found = 1;
result = err; result = err;
if (line) if (line)
...@@ -216,19 +215,29 @@ static int ftp_send_command(FTPContext *s, const char *command, ...@@ -216,19 +215,29 @@ static int ftp_send_command(FTPContext *s, const char *command,
s->conn_control_block_flag = 0; s->conn_control_block_flag = 0;
if ((err = ffurl_write(s->conn_control, command, strlen(command))) < 0) if ((err = ffurl_write(s->conn_control, command, strlen(command))) < 0)
return err; return err;
if (!err)
return -1;
/* return status */ /* return status */
if (response_codes) {
return ftp_status(s, response, response_codes); return ftp_status(s, response, response_codes);
}
return 0;
} }
static void ftp_close_both_connections(FTPContext *s) static void ftp_close_data_connection(FTPContext *s)
{ {
ffurl_closep(&s->conn_control);
ffurl_closep(&s->conn_data); ffurl_closep(&s->conn_data);
s->position = 0; s->position = 0;
s->state = DISCONNECTED; s->state = DISCONNECTED;
} }
static void ftp_close_both_connections(FTPContext *s)
{
ffurl_closep(&s->conn_control);
ftp_close_data_connection(s);
}
static int ftp_auth(FTPContext *s) static int ftp_auth(FTPContext *s)
{ {
const char *user = NULL, *pass = NULL; const char *user = NULL, *pass = NULL;
...@@ -445,8 +454,7 @@ static int ftp_connect_control_connection(URLContext *h) ...@@ -445,8 +454,7 @@ static int ftp_connect_control_connection(URLContext *h)
/* consume all messages from server */ /* consume all messages from server */
if (ftp_status(s, NULL, connect_codes) != 220) { if (ftp_status(s, NULL, connect_codes) != 220) {
av_log(h, AV_LOG_ERROR, "FTP server not ready for new users\n"); av_log(h, AV_LOG_ERROR, "FTP server not ready for new users\n");
err = AVERROR(EACCES); return AVERROR(EACCES);
return err;
} }
if ((err = ftp_auth(s)) < 0) { if ((err = ftp_auth(s)) < 0) {
...@@ -497,12 +505,40 @@ static int ftp_connect_data_connection(URLContext *h) ...@@ -497,12 +505,40 @@ static int ftp_connect_data_connection(URLContext *h)
static int ftp_abort(URLContext *h) static int ftp_abort(URLContext *h)
{ {
const char *command = "ABOR\r\n";
int err; int err;
ftp_close_both_connections(h->priv_data); const int abor_codes[] = {225, 226, 0};
FTPContext *s = h->priv_data;
/* According to RCF 959:
"ABOR command tells the server to abort the previous FTP
service command and any associated transfer of data."
There are FTP server implementations that don't response
to any commands during data transfer in passive mode (including ABOR).
This implementation closes data connection by force.
*/
if (ftp_send_command(s, command, NULL, NULL) < 0) {
ftp_close_both_connections(s);
if ((err = ftp_connect_control_connection(h)) < 0) { if ((err = ftp_connect_control_connection(h)) < 0) {
av_log(h, AV_LOG_ERROR, "Reconnect failed.\n"); av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
return err; return err;
} }
} else {
ftp_close_data_connection(s);
}
if (ftp_status(s, NULL, abor_codes) < 225) {
/* wu-ftpd also closes control connection after data connection closing */
ffurl_closep(&s->conn_control);
if ((err = ftp_connect_control_connection(h)) < 0) {
av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
return err;
}
}
return 0; return 0;
} }
...@@ -585,12 +621,8 @@ static int64_t ftp_seek(URLContext *h, int64_t pos, int whence) ...@@ -585,12 +621,8 @@ static int64_t ftp_seek(URLContext *h, int64_t pos, int whence)
new_pos = FFMIN(s->filesize, new_pos); new_pos = FFMIN(s->filesize, new_pos);
if (new_pos != s->position) { if (new_pos != s->position) {
/* XXX: Full abort is a save solution here.
Some optimalizations are possible, but may lead to crazy states of FTP server.
The worst scenario would be when FTP server closed both connection due to no transfer. */
if ((err = ftp_abort(h)) < 0) if ((err = ftp_abort(h)) < 0)
return err; return err;
s->position = new_pos; s->position = new_pos;
} }
return new_pos; return new_pos;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment