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.
This commit is contained in:
Lukasz Marek 2013-05-27 20:53:27 +02:00
parent c84d6aa2f6
commit 1931c2d265

View File

@ -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;