summaryrefslogtreecommitdiffstats
path: root/stream
diff options
context:
space:
mode:
Diffstat (limited to 'stream')
-rw-r--r--stream/stream_ftp.c104
1 files changed, 73 insertions, 31 deletions
diff --git a/stream/stream_ftp.c b/stream/stream_ftp.c
index 8485e0e969..6879881b8e 100644
--- a/stream/stream_ftp.c
+++ b/stream/stream_ftp.c
@@ -32,6 +32,8 @@
#include <winsock2.h>
#endif
+#include <libavutil/avutil.h>
+
#include "core/mp_msg.h"
#include "network.h"
#include "stream.h"
@@ -50,6 +52,7 @@ static struct stream_priv_s {
int handle;
int cavail,cleft;
char *buf;
+ char *cmd_buf;
} stream_priv_dflts = {
"anonymous","no@spam",
NULL,
@@ -58,11 +61,14 @@ static struct stream_priv_s {
NULL,
NULL,
- 0,
+ -1,
0,0,
- NULL
+ NULL,
+ NULL,
};
+#define CMD_BUFSIZE 8192
+
#define BUFSIZE 2048
#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
@@ -103,6 +109,14 @@ static int fd_can_read(int fd,int timeout) {
/*
* read a line of text
*
+ * If the line is too long to fit in the buffer, provided via parameters
+ * buf and max, the remaining characters are skipped. So the next call to
+ * this function is synchronized to the start of the following response
+ * line.
+ *
+ * The parameter buf will always be initialized as long as max is bigger
+ * then 1. If nothing is read it will contain an empty string.
+ *
* return -1 on error or bytecount
*/
static int readline(char *buf,int max,struct stream_priv_s *ctl)
@@ -111,9 +125,14 @@ static int readline(char *buf,int max,struct stream_priv_s *ctl)
char *end,*bp=buf;
int eof = 0;
+ if (max <= 0) {
+ return -1;
+ }
+ *bp = '\0';
+
do {
if (ctl->cavail > 0) {
- x = (max >= ctl->cavail) ? ctl->cavail : max-1;
+ x = FFMIN(ctl->cavail, max-1);
end = memccpy(bp,ctl->cget,'\n',x);
if (end != NULL)
x = end - bp;
@@ -134,8 +153,18 @@ static int readline(char *buf,int max,struct stream_priv_s *ctl)
}
}
if (max == 1) {
- *buf = '\0';
- break;
+ char *q = memchr(ctl->cget, '\n', ctl->cavail);
+
+ if (q) { // found EOL: update state and return
+ ++q;
+ ctl->cavail -= q - ctl->cget;
+ ctl->cget = q;
+
+ break;
+ }
+
+ // receive more data to find end of current line
+ ctl->cget = ctl->cput;
}
if (ctl->cput == ctl->cget) {
ctl->cput = ctl->cget = ctl->buf;
@@ -179,13 +208,14 @@ static int readresp(struct stream_priv_s* ctl,char* rsp)
{
static char response[256];
char match[5];
- int r;
+ int r, len;
- if (readline(response,256,ctl) == -1)
+ len = readline(response,256,ctl);
+ if (rsp) strcpy(rsp,response);
+ if (len == -1)
return 0;
r = atoi(response)/100;
- if(rsp) strcpy(rsp,response);
mp_msg(MSGT_STREAM,MSGL_V, "[ftp] < %s",response);
@@ -263,7 +293,7 @@ static int FtpOpenPort(struct stream_priv_s* p) {
static int FtpOpenData(stream_t* s,int64_t newpos) {
struct stream_priv_s* p = s->priv;
int resp;
- char str[256],rsp_txt[256];
+ char rsp_txt[256];
// Open a new connection
s->fd = FtpOpenPort(p);
@@ -271,21 +301,21 @@ static int FtpOpenData(stream_t* s,int64_t newpos) {
if(s->fd < 0) return 0;
if(newpos > 0) {
- snprintf(str,255,"REST %"PRId64, (int64_t)newpos);
+ snprintf(p->cmd_buf,CMD_BUFSIZE - 1,"REST %"PRId64, (int64_t)newpos);
- resp = FtpSendCmd(str,p,rsp_txt);
+ resp = FtpSendCmd(p->cmd_buf,p,rsp_txt);
if(resp != 3) {
- mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+ mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt);
newpos = 0;
}
}
// Get the file
- snprintf(str,255,"RETR %s",p->filename);
- resp = FtpSendCmd(str,p,rsp_txt);
+ snprintf(p->cmd_buf,CMD_BUFSIZE - 1,"RETR %s",p->filename);
+ resp = FtpSendCmd(p->cmd_buf,p,rsp_txt);
if(resp != 1) {
- mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+ mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt);
return 0;
}
@@ -333,7 +363,7 @@ static int seek(stream_t *s,int64_t newpos) {
// First close the fd
closesocket(s->fd);
- s->fd = 0;
+ s->fd = -1;
// Send send the telnet sequence needed to make the server react
@@ -369,15 +399,18 @@ static void close_f(stream_t *s) {
if(!p) return;
- if(s->fd > 0) {
+ if(s->fd >= 0) {
closesocket(s->fd);
- s->fd = 0;
+ s->fd = -1;
}
- FtpSendCmd("QUIT",p,NULL);
+ if (p->handle >= 0) {
+ FtpSendCmd("QUIT", p, NULL);
+ closesocket(p->handle);
+ }
- if(p->handle) closesocket(p->handle);
free(p->buf);
+ free(p->cmd_buf);
m_struct_free(&stream_opts,p);
}
@@ -388,7 +421,7 @@ static int open_f(stream_t *stream,int mode, void* opts, int* file_format) {
int resp;
int64_t len = 0;
struct stream_priv_s* p = (struct stream_priv_s*)opts;
- char str[256],rsp_txt[256];
+ char rsp_txt[256];
if(mode != STREAM_READ) {
mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Unknown open mode %d\n",mode);
@@ -402,6 +435,16 @@ static int open_f(stream_t *stream,int mode, void* opts, int* file_format) {
return STREAM_ERROR;
}
+ // Allocate buffers
+ p->buf = malloc(BUFSIZE);
+ p->cmd_buf = malloc(CMD_BUFSIZE);
+
+ if (!p->buf || !p->cmd_buf) {
+ close_f(stream);
+ m_struct_free(&stream_opts,opts);
+ return STREAM_ERROR;
+ }
+
// Open the control connection
p->handle = connect2Server(p->host,p->port,1);
@@ -413,7 +456,6 @@ static int open_f(stream_t *stream,int mode, void* opts, int* file_format) {
// We got a connection, let's start serious things
stream->fd = -1;
stream->priv = p;
- p->buf = malloc(BUFSIZE);
if (readresp(p, NULL) == 0) {
close_f(stream);
@@ -421,20 +463,20 @@ static int open_f(stream_t *stream,int mode, void* opts, int* file_format) {
}
// Login
- snprintf(str,255,"USER %s",p->user);
- resp = FtpSendCmd(str,p,rsp_txt);
+ snprintf(p->cmd_buf,CMD_BUFSIZE - 1,"USER %s",p->user);
+ resp = FtpSendCmd(p->cmd_buf,p,rsp_txt);
// password needed
if(resp == 3) {
- snprintf(str,255,"PASS %s",p->pass);
- resp = FtpSendCmd(str,p,rsp_txt);
+ snprintf(p->cmd_buf,CMD_BUFSIZE - 1,"PASS %s",p->pass);
+ resp = FtpSendCmd(p->cmd_buf,p,rsp_txt);
if(resp != 2) {
- mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+ mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt);
close_f(stream);
return STREAM_ERROR;
}
} else if(resp != 2) {
- mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+ mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt);
close_f(stream);
return STREAM_ERROR;
}
@@ -448,10 +490,10 @@ static int open_f(stream_t *stream,int mode, void* opts, int* file_format) {
}
// Get the filesize
- snprintf(str,255,"SIZE %s",p->filename);
- resp = FtpSendCmd(str,p,rsp_txt);
+ snprintf(p->cmd_buf,CMD_BUFSIZE - 1,"SIZE %s",p->filename);
+ resp = FtpSendCmd(p->cmd_buf,p,rsp_txt);
if(resp != 2) {
- mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+ mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt);
} else {
int dummy;
sscanf(rsp_txt,"%d %"SCNd64,&dummy,&len);