mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-04-14 00:58:38 +02:00
* https://github.com/lukaszmluki/ffmpeg: ftp: warning about pure-ftp server used as and output ftp: comments ftp: remove unused headers ftp: fix interrupt callback misuse Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
commit
1816f5509e
@ -18,15 +18,12 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "libavutil/avstring.h"
|
||||
#include "libavutil/time.h"
|
||||
#include "avformat.h"
|
||||
#include "internal.h"
|
||||
#include "network.h"
|
||||
#include "os_support.h"
|
||||
#include "url.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/bprint.h"
|
||||
|
||||
#define CONTROL_BUFFER_SIZE 1024
|
||||
#define CREDENTIALS_BUFFER_SIZE 128
|
||||
@ -42,8 +39,6 @@ typedef enum {
|
||||
typedef struct {
|
||||
const AVClass *class;
|
||||
URLContext *conn_control; /**< Control connection */
|
||||
int conn_control_block_flag; /**< Controls block/unblock mode of data connection */
|
||||
AVIOInterruptCB conn_control_interrupt_cb; /**< Controls block/unblock mode of data connection */
|
||||
URLContext *conn_data; /**< Data connection, NULL when not connected */
|
||||
uint8_t control_buffer[CONTROL_BUFFER_SIZE]; /**< Control connection buffer */
|
||||
uint8_t *control_buf_ptr, *control_buf_end;
|
||||
@ -77,18 +72,10 @@ static const AVClass ftp_context_class = {
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
static int ftp_conn_control_block_control(void *data)
|
||||
{
|
||||
FTPContext *s = data;
|
||||
return s->conn_control_block_flag;
|
||||
}
|
||||
|
||||
static int ftp_getc(FTPContext *s)
|
||||
{
|
||||
int len;
|
||||
if (s->control_buf_ptr >= s->control_buf_end) {
|
||||
if (s->conn_control_block_flag)
|
||||
return AVERROR_EXIT;
|
||||
len = ffurl_read(s->conn_control, s->control_buffer, CONTROL_BUFFER_SIZE);
|
||||
if (len < 0) {
|
||||
return len;
|
||||
@ -106,12 +93,10 @@ static int ftp_get_line(FTPContext *s, char *line, int line_size)
|
||||
{
|
||||
int ch;
|
||||
char *q = line;
|
||||
int ori_block_flag = s->conn_control_block_flag;
|
||||
|
||||
for (;;) {
|
||||
ch = ftp_getc(s);
|
||||
if (ch < 0) {
|
||||
s->conn_control_block_flag = ori_block_flag;
|
||||
return ch;
|
||||
}
|
||||
if (ch == '\n') {
|
||||
@ -119,86 +104,61 @@ static int ftp_get_line(FTPContext *s, char *line, int line_size)
|
||||
if (q > line && q[-1] == '\r')
|
||||
q--;
|
||||
*q = '\0';
|
||||
|
||||
s->conn_control_block_flag = ori_block_flag;
|
||||
return 0;
|
||||
} else {
|
||||
s->conn_control_block_flag = 0; /* line need to be finished */
|
||||
if ((q - line) < line_size - 1)
|
||||
*q++ = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ftp_flush_control_input(FTPContext *s)
|
||||
{
|
||||
char buf[CONTROL_BUFFER_SIZE];
|
||||
int err, ori_block_flag = s->conn_control_block_flag;
|
||||
|
||||
s->conn_control_block_flag = 1;
|
||||
do {
|
||||
err = ftp_get_line(s, buf, sizeof(buf));
|
||||
} while (!err);
|
||||
|
||||
s->conn_control_block_flag = ori_block_flag;
|
||||
|
||||
if (err < 0 && err != AVERROR_EXIT)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine returns ftp server response code.
|
||||
* Server may send more than one response for a certain command, following priorities are used:
|
||||
* - When pref_codes are set then pref_code is return if occurred. (expected result)
|
||||
* - 0 is returned when no pref_codes or not occurred
|
||||
* Server may send more than one response for a certain command.
|
||||
* First expected code is returned.
|
||||
*/
|
||||
static int ftp_status(FTPContext *s, char **line, const int response_codes[])
|
||||
{
|
||||
int err, i, result = 0, pref_code_found = 0, wait_count = 100;
|
||||
int err, i, dash = 0, result = 0, code_found = 0;
|
||||
char buf[CONTROL_BUFFER_SIZE];
|
||||
AVBPrint line_buffer;
|
||||
|
||||
/* Set blocking mode */
|
||||
s->conn_control_block_flag = 0;
|
||||
for (;;) {
|
||||
if (line)
|
||||
av_bprint_init(&line_buffer, 0, AV_BPRINT_SIZE_AUTOMATIC);
|
||||
|
||||
while (!code_found || dash) {
|
||||
if ((err = ftp_get_line(s, buf, sizeof(buf))) < 0) {
|
||||
if (err == AVERROR_EXIT) {
|
||||
if (!pref_code_found && wait_count--) {
|
||||
av_usleep(10000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
av_bprint_finalize(&line_buffer, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
av_log(s, AV_LOG_DEBUG, "%s\n", buf);
|
||||
|
||||
if (!pref_code_found) {
|
||||
if (strlen(buf) < 3)
|
||||
if (strlen(buf) < 4)
|
||||
continue;
|
||||
|
||||
err = 0;
|
||||
for (i = 0; i < 3; ++i) {
|
||||
if (buf[i] < '0' || buf[i] > '9')
|
||||
continue;
|
||||
err *= 10;
|
||||
err += buf[i] - '0';
|
||||
}
|
||||
dash = !!(buf[3] == '-');
|
||||
|
||||
err = 0;
|
||||
for (i = 0; i < 3; ++i) {
|
||||
if (buf[i] < '0' || buf[i] > '9')
|
||||
continue;
|
||||
err *= 10;
|
||||
err += buf[i] - '0';
|
||||
}
|
||||
|
||||
for (i = 0; response_codes[i]; ++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;
|
||||
result = err;
|
||||
if (line)
|
||||
*line = av_strdup(buf);
|
||||
break;
|
||||
}
|
||||
for (i = 0; response_codes[i]; ++i) {
|
||||
if (err == response_codes[i]) {
|
||||
if (line)
|
||||
av_bprintf(&line_buffer, "%s", buf);
|
||||
code_found = 1;
|
||||
result = err;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (line)
|
||||
av_bprint_finalize(&line_buffer, line);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -207,12 +167,6 @@ static int ftp_send_command(FTPContext *s, const char *command,
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Flush control connection input to get rid of non relevant responses if any */
|
||||
if ((err = ftp_flush_control_input(s)) < 0)
|
||||
return err;
|
||||
|
||||
/* send command in blocking mode */
|
||||
s->conn_control_block_flag = 0;
|
||||
if ((err = ffurl_write(s->conn_control, command, strlen(command))) < 0)
|
||||
return err;
|
||||
if (!err)
|
||||
@ -428,14 +382,12 @@ static int ftp_restart(FTPContext *s, int64_t pos)
|
||||
|
||||
static int ftp_connect_control_connection(URLContext *h)
|
||||
{
|
||||
char buf[CONTROL_BUFFER_SIZE], opts_format[20];
|
||||
char buf[CONTROL_BUFFER_SIZE], opts_format[20], *response = NULL;
|
||||
int err;
|
||||
AVDictionary *opts = NULL;
|
||||
FTPContext *s = h->priv_data;
|
||||
const int connect_codes[] = {220, 0};
|
||||
|
||||
s->conn_control_block_flag = 0;
|
||||
|
||||
if (!s->conn_control) {
|
||||
ff_url_join(buf, sizeof(buf), "tcp", NULL,
|
||||
s->hostname, s->server_control_port, NULL);
|
||||
@ -444,19 +396,24 @@ static int ftp_connect_control_connection(URLContext *h)
|
||||
av_dict_set(&opts, "timeout", opts_format, 0);
|
||||
} /* if option is not given, don't pass it and let tcp use its own default */
|
||||
err = ffurl_open(&s->conn_control, buf, AVIO_FLAG_READ_WRITE,
|
||||
&s->conn_control_interrupt_cb, &opts);
|
||||
&h->interrupt_callback, &opts);
|
||||
av_dict_free(&opts);
|
||||
if (err < 0) {
|
||||
av_log(h, AV_LOG_ERROR, "Cannot open control connection\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* consume all messages from server */
|
||||
if (ftp_status(s, NULL, connect_codes) != 220) {
|
||||
/* check if server is ready */
|
||||
if (ftp_status(s, ((h->flags & AVIO_FLAG_WRITE) ? &response : NULL), connect_codes) != 220) {
|
||||
av_log(h, AV_LOG_ERROR, "FTP server not ready for new users\n");
|
||||
return AVERROR(EACCES);
|
||||
}
|
||||
|
||||
if ((h->flags & AVIO_FLAG_WRITE) && av_stristr(response, "pure-ftpd")) {
|
||||
av_log(h, AV_LOG_WARNING, "Pure-FTPd server is used as an output protocol. It is known issue this implementation may produce incorrect content and it cannot be fixed at this moment.");
|
||||
}
|
||||
av_free(response);
|
||||
|
||||
if ((err = ftp_auth(s)) < 0) {
|
||||
av_log(h, AV_LOG_ERROR, "FTP authentication failed\n");
|
||||
return err;
|
||||
@ -489,7 +446,7 @@ static int ftp_connect_data_connection(URLContext *h)
|
||||
snprintf(opts_format, sizeof(opts_format), "%d", s->rw_timeout);
|
||||
av_dict_set(&opts, "timeout", opts_format, 0);
|
||||
} /* if option is not given, don't pass it and let tcp use its own default */
|
||||
err = ffurl_open(&s->conn_data, buf, AVIO_FLAG_READ_WRITE,
|
||||
err = ffurl_open(&s->conn_data, buf, h->flags,
|
||||
&h->interrupt_callback, &opts);
|
||||
av_dict_free(&opts);
|
||||
if (err < 0)
|
||||
@ -553,8 +510,6 @@ static int ftp_open(URLContext *h, const char *url, int flags)
|
||||
s->state = DISCONNECTED;
|
||||
s->filesize = -1;
|
||||
s->position = 0;
|
||||
s->conn_control_interrupt_cb.opaque = s;
|
||||
s->conn_control_interrupt_cb.callback = ftp_conn_control_block_control;
|
||||
|
||||
av_url_split(proto, sizeof(proto),
|
||||
s->credencials, sizeof(s->credencials),
|
||||
@ -620,6 +575,7 @@ static int64_t ftp_seek(URLContext *h, int64_t pos, int whence)
|
||||
if (h->is_streamed)
|
||||
return AVERROR(EIO);
|
||||
|
||||
/* XXX: Simulate behaviour of lseek in file protocol, which could be treated as a reference */
|
||||
new_pos = FFMAX(0, new_pos);
|
||||
fake_pos = s->filesize != -1 ? FFMIN(new_pos, s->filesize) : new_pos;
|
||||
|
||||
@ -639,6 +595,7 @@ static int ftp_read(URLContext *h, unsigned char *buf, int size)
|
||||
av_dlog(h, "ftp protocol read %d bytes\n", size);
|
||||
retry:
|
||||
if (s->state == DISCONNECTED) {
|
||||
/* optimization */
|
||||
if (s->position >= s->filesize)
|
||||
return 0;
|
||||
if ((err = ftp_connect_data_connection(h)) < 0)
|
||||
@ -656,6 +613,7 @@ static int ftp_read(URLContext *h, unsigned char *buf, int size)
|
||||
s->position += read;
|
||||
if (s->position >= s->filesize) {
|
||||
/* server will terminate, but keep current position to avoid madness */
|
||||
/* save position to restart from it */
|
||||
int64_t pos = s->position;
|
||||
if (ftp_abort(h) < 0) {
|
||||
s->position = pos;
|
||||
|
Loading…
x
Reference in New Issue
Block a user