diff options
author | Lukasz Marek <lukasz.m.luki@gmail.com> | 2013-05-27 20:53:27 +0200 |
---|---|---|
committer | Lukasz Marek <lukasz.m.luki@gmail.com> | 2013-05-31 16:40:03 +0200 |
commit | 1931c2d2654fc6244232d4828ebfafeb414dbb26 (patch) | |
tree | a9b88a089cda524b5b7068b2f36b854c74c92b46 /libavformat/ftp.c | |
parent | c84d6aa2f63f014a1c08f4adf67c462b98f68028 (diff) | |
download | ffmpeg-1931c2d2654fc6244232d4828ebfafeb414dbb26.tar.gz |
ftp: reconnect on read
FTP server may disconnect after some period of time when no transfer is done.
FTP protocol should reconnect and seek to last position.
Diffstat (limited to 'libavformat/ftp.c')
-rw-r--r-- | libavformat/ftp.c | 125 |
1 files changed, 73 insertions, 52 deletions
diff --git a/libavformat/ftp.c b/libavformat/ftp.c index da9408a2c3..e497c1a9de 100644 --- a/libavformat/ftp.c +++ b/libavformat/ftp.c @@ -38,7 +38,6 @@ typedef enum { DISCONNECTED } FTPState; - typedef struct { const AVClass *class; URLContext *conn_control; /**< Control connection */ @@ -499,57 +498,6 @@ static int ftp_open(URLContext *h, const char *url, int flags) return err; } -static int ftp_read(URLContext *h, unsigned char *buf, int size) -{ - FTPContext *s = h->priv_data; - int read; - - av_dlog(h, "ftp protocol read %d bytes\n", size); - - if (s->state == READY) { - ftp_retrieve(s); - } - if (s->conn_data && s->state == DOWNLOADING) { - read = ffurl_read(s->conn_data, buf, size); - if (read >= 0) { - s->position += read; - if (s->position >= s->filesize) { - ffurl_closep(&s->conn_data); - s->state = DISCONNECTED; - if (ftp_status(s, NULL, NULL, NULL,NULL, 226) != 226) - return AVERROR(EIO); - } - } - return read; - } - - av_log(h, AV_LOG_DEBUG, "FTP read failed\n"); - return AVERROR(EIO); -} - -static int ftp_write(URLContext *h, const unsigned char *buf, int size) -{ - FTPContext *s = h->priv_data; - int written; - - av_dlog(h, "ftp protocol write %d bytes\n", size); - - if (s->state == READY) { - ftp_store(s); - } - if (s->conn_data && s->state == UPLOADING) { - written = ffurl_write(s->conn_data, buf, size); - if (written > 0) { - s->position += written; - s->filesize = FFMAX(s->filesize, s->position); - } - return written; - } - - av_log(h, AV_LOG_ERROR, "FTP write failed\n"); - return AVERROR(EIO); -} - static int64_t ftp_seek(URLContext *h, int64_t pos, int whence) { FTPContext *s = h->priv_data; @@ -618,6 +566,79 @@ static int64_t ftp_seek(URLContext *h, int64_t pos, int whence) return new_pos; } +static int ftp_read(URLContext *h, unsigned char *buf, int size) +{ + FTPContext *s = h->priv_data; + int read, err, retry_done = 0; + + av_dlog(h, "ftp protocol read %d bytes\n", size); + retry: + if (s->state == READY) { + ftp_retrieve(s); + } + if (s->conn_data && s->state == DOWNLOADING) { + read = ffurl_read(s->conn_data, buf, size); + if (read >= 0) { + s->position += read; + if (s->position >= s->filesize) { + ffurl_closep(&s->conn_data); + s->state = DISCONNECTED; + if (ftp_status(s, NULL, NULL, NULL,NULL, 226) != 226) + return AVERROR(EIO); + } + } + if (!read && s->position < s->filesize && !h->is_streamed) { + /* Server closed connection. Probably due to inactivity */ + /* TODO: Consider retry before reconnect */ + int64_t pos = s->position; + av_log(h, AV_LOG_INFO, "Reconnect to FTP server.\n"); + ffurl_closep(&s->conn_control); + ffurl_closep(&s->conn_data); + s->position = 0; + s->state = DISCONNECTED; + if ((err = ftp_connect_control_connection(h)) < 0) { + av_log(h, AV_LOG_ERROR, "Reconnect failed\n"); + return err; + } + if ((err = ftp_seek(h, pos, SEEK_SET)) < 0) { + av_dlog(h, "Seek failed after reconnect\n"); + return err; + } + if (!retry_done) { + retry_done = 1; + goto retry; + } + } + return read; + } + + av_log(h, AV_LOG_DEBUG, "FTP read failed\n"); + return AVERROR(EIO); +} + +static int ftp_write(URLContext *h, const unsigned char *buf, int size) +{ + FTPContext *s = h->priv_data; + int written; + + av_dlog(h, "ftp protocol write %d bytes\n", size); + + if (s->state == READY) { + ftp_store(s); + } + if (s->conn_data && s->state == UPLOADING) { + written = ffurl_write(s->conn_data, buf, size); + if (written > 0) { + s->position += written; + s->filesize = FFMAX(s->filesize, s->position); + } + return written; + } + + av_log(h, AV_LOG_ERROR, "FTP write failed\n"); + return AVERROR(EIO); +} + static int ftp_close(URLContext *h) { FTPContext *s = h->priv_data; |