diff options
Diffstat (limited to 'stream/stream_ftp.c')
-rw-r--r-- | stream/stream_ftp.c | 520 |
1 files changed, 0 insertions, 520 deletions
diff --git a/stream/stream_ftp.c b/stream/stream_ftp.c deleted file mode 100644 index 77537e08fd..0000000000 --- a/stream/stream_ftp.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> -#if !HAVE_WINSOCK2_H -#include <sys/socket.h> -#else -#include <winsock2.h> -#endif - -#include <libavutil/common.h> - -#include "core/mp_msg.h" -#include "network.h" -#include "stream.h" -#include "core/m_option.h" -#include "core/m_struct.h" -#include "tcp.h" - -static struct stream_priv_s { - char* user; - char* pass; - char* host; - int port; - char* filename; - - char *cput,*cget; - int handle; - int cavail,cleft; - char *buf; - char *cmd_buf; -} stream_priv_dflts = { - .user = "anonymous", - .pass = "no@spam", - .port = 21, - .handle = -1, -}; - -#define CMD_BUFSIZE 8192 - -#define BUFSIZE 2048 - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -/// URL definition -static const m_option_t stream_opts_fields[] = { - {"username", ST_OFF(user), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"password", ST_OFF(pass), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"hostname", ST_OFF(host), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - {"port", ST_OFF(port), CONF_TYPE_INT, 0, 0 ,65635, NULL}, - {"filename", ST_OFF(filename), CONF_TYPE_STRING, 0, 0 ,0, NULL}, - { NULL, NULL, 0, 0, 0, 0, NULL } -}; -static const struct m_struct_st stream_opts = { - "ftp", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -#define TELNET_IAC 255 /* interpret as command: */ -#define TELNET_IP 244 /* interrupt process--permanently */ -#define TELNET_SYNCH 242 /* for telfunc calls */ - -// Check if there is something to read on a fd. This avoid hanging -// forever if the network stop responding. -static int fd_can_read(int fd,int timeout) { - fd_set fds; - struct timeval tv; - - FD_ZERO(&fds); - FD_SET(fd,&fds); - tv.tv_sec = timeout; - tv.tv_usec = 0; - - return select(fd+1, &fds, NULL, NULL, &tv) > 0; -} - -/* - * 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) -{ - int x,retval = 0; - char *end,*bp=buf; - int eof = 0; - - if (max <= 0) { - return -1; - } - *bp = '\0'; - - do { - if (ctl->cavail > 0) { - x = FFMIN(ctl->cavail, max-1); - end = memccpy(bp,ctl->cget,'\n',x); - if (end != NULL) - x = end - bp; - retval += x; - bp += x; - *bp = '\0'; - max -= x; - ctl->cget += x; - ctl->cavail -= x; - if (end != NULL) { - bp -= 2; - if (strcmp(bp,"\r\n") == 0) { - *bp++ = '\n'; - *bp++ = '\0'; - --retval; - } - break; - } - } - if (max == 1) { - 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; - ctl->cavail = 0; - ctl->cleft = BUFSIZE; - } - if(eof) { - if (retval == 0) - retval = -1; - break; - } - - if(!fd_can_read(ctl->handle, 15)) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] read timed out\n"); - retval = -1; - break; - } - - if ((x = recv(ctl->handle,ctl->cput,ctl->cleft,0)) == -1) { - mp_msg(MSGT_STREAM,MSGL_ERR, "[ftp] read error: %s\n",strerror(errno)); - retval = -1; - break; - } - if (x == 0) - eof = 1; - ctl->cleft -= x; - ctl->cavail += x; - ctl->cput += x; - } while (1); - - return retval; -} - -/* - * read a response from the server - * - * return 0 if first char doesn't match - * return 1 if first char matches - */ -static int readresp(struct stream_priv_s* ctl,char* rsp) -{ - static char response[256]; - char match[5]; - int r, len; - - len = readline(response,256,ctl); - if (rsp) strcpy(rsp,response); - if (len == -1) - return 0; - - r = atoi(response)/100; - - mp_msg(MSGT_STREAM,MSGL_V, "[ftp] < %s",response); - - if (response[3] == '-') { - strncpy(match,response,3); - match[3] = ' '; - match[4] = '\0'; - do { - if (readline(response,256,ctl) == -1) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Control socket read failed\n"); - return 0; - } - mp_msg(MSGT_OPEN,MSGL_V, "[ftp] < %s",response); - } while (strncmp(response,match,4)); - } - return r; -} - - -static int FtpSendCmd(const char *cmd, struct stream_priv_s *nControl,char* rsp) -{ - int l = strlen(cmd); - int hascrlf = cmd[l - 2] == '\r' && cmd[l - 1] == '\n'; - - if(hascrlf && l == 2) mp_msg(MSGT_STREAM,MSGL_V, "\n"); - else mp_msg(MSGT_STREAM,MSGL_V, "[ftp] > %s",cmd); - while(l > 0) { - int s = send(nControl->handle,cmd,l,DEFAULT_SEND_FLAGS); - - if(s <= 0) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] write error: %s\n",strerror(errno)); - return 0; - } - - cmd += s; - l -= s; - } - - if (hascrlf) - return readresp(nControl,rsp); - else - return FtpSendCmd("\r\n", nControl, rsp); -} - -static int FtpOpenPort(struct stream_priv_s* p) { - int resp,fd; - char rsp_txt[256]; - char* par,str[128]; - int num[6]; - - resp = FtpSendCmd("PASV",p,rsp_txt); - if(resp != 2) { - mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command 'PASV' failed: %s\n",rsp_txt); - return 0; - } - - par = strchr(rsp_txt,'('); - - if(!par || !par[0] || !par[1]) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] invalid server response: %s ??\n",rsp_txt); - return 0; - } - - sscanf(par+1,"%u,%u,%u,%u,%u,%u",&num[0],&num[1],&num[2], - &num[3],&num[4],&num[5]); - snprintf(str,sizeof(str),"%d.%d.%d.%d",num[0],num[1],num[2],num[3]); - fd = connect2Server(str,(num[4]<<8)+num[5],0); - - if(fd < 0) - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] failed to create data connection\n"); - - return fd; -} - -static int FtpOpenData(stream_t* s,int64_t newpos) { - struct stream_priv_s* p = s->priv; - int resp; - char rsp_txt[256]; - - // Open a new connection - s->fd = FtpOpenPort(p); - - if(s->fd < 0) return 0; - - if(newpos > 0) { - snprintf(p->cmd_buf,CMD_BUFSIZE,"REST %"PRId64, (int64_t)newpos); - - resp = FtpSendCmd(p->cmd_buf,p,rsp_txt); - if(resp != 3) { - mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",p->cmd_buf,rsp_txt); - newpos = 0; - } - } - - // Get the file - snprintf(p->cmd_buf,CMD_BUFSIZE,"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",p->cmd_buf,rsp_txt); - return 0; - } - - s->pos = newpos; - return 1; -} - -static int fill_buffer(stream_t *s, char* buffer, int max_len){ - int r; - - if(s->fd < 0 && !FtpOpenData(s,s->pos)) - return -1; - - if(!fd_can_read(s->fd, 15)) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] read timed out\n"); - return -1; - } - - r = recv(s->fd,buffer,max_len,0); - return (r <= 0) ? -1 : r; -} - -static int seek(stream_t *s,int64_t newpos) { - struct stream_priv_s* p = s->priv; - int resp; - char rsp_txt[256]; - - if(s->pos > s->end_pos) { - return 0; - } - - // Check to see if the server did not already terminate the transfer - if(fd_can_read(p->handle, 0)) { - if(readresp(p,rsp_txt) != 2) - mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] Warning the server didn't finished the transfer correctly: %s\n",rsp_txt); - closesocket(s->fd); - s->fd = -1; - } - - // Close current download - if(s->fd >= 0) { - static const char pre_cmd[]={TELNET_IAC,TELNET_IP,TELNET_IAC,TELNET_SYNCH}; - //int fl; - - // First close the fd - closesocket(s->fd); - s->fd = -1; - - // Send send the telnet sequence needed to make the server react - - // Dunno if this is really needed, lftp have it. I let - // it here in case it turn out to be needed on some other OS - //fl=fcntl(p->handle,F_GETFL); - //fcntl(p->handle,F_SETFL,fl&~O_NONBLOCK); - - // send only first byte as OOB due to OOB braindamage in many unices - send(p->handle,pre_cmd,1,MSG_OOB|DEFAULT_SEND_FLAGS); - send(p->handle,pre_cmd+1,sizeof(pre_cmd)-1,DEFAULT_SEND_FLAGS); - - //fcntl(p->handle,F_SETFL,fl); - - // Get the 426 Transfer aborted - // Or the 226 Transfer complete - resp = readresp(p,rsp_txt); - if(resp != 4 && resp != 2) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Server didn't abort correctly: %s\n",rsp_txt); - return 0; - } - // Send the ABOR command - // Ignore the return code as sometimes it fail with "nothing to abort" - FtpSendCmd("ABOR",p,rsp_txt); - } - return FtpOpenData(s,newpos); -} - - -static void close_f(stream_t *s) { - struct stream_priv_s* p = s->priv; - - if(!p) return; - - if(s->fd >= 0) { - closesocket(s->fd); - s->fd = -1; - } - - if (p->handle >= 0) { - FtpSendCmd("QUIT", p, NULL); - closesocket(p->handle); - } - - free(p->buf); - free(p->cmd_buf); - - m_struct_free(&stream_opts,p); -} - - - -static int open_f(stream_t *stream,int mode, void* opts, av_unused int* file_format) { - int resp; - int64_t len = 0; - struct stream_priv_s* p = opts; - char rsp_txt[256]; - - if(mode != STREAM_READ) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Unknown open mode %d\n",mode); - m_struct_free(&stream_opts,opts); - return STREAM_UNSUPPORTED; - } - - if(!p->filename || !p->host) { - mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Bad url\n"); - m_struct_free(&stream_opts,opts); - 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); - - if(p->handle < 0) { - m_struct_free(&stream_opts,opts); - return STREAM_ERROR; - } - - // We got a connection, let's start serious things - stream->fd = -1; - stream->priv = p; - - if (readresp(p, NULL) == 0) { - close_f(stream); - return STREAM_ERROR; - } - - // Login - snprintf(p->cmd_buf,CMD_BUFSIZE,"USER %s",p->user); - resp = FtpSendCmd(p->cmd_buf,p,rsp_txt); - - // password needed - if(resp == 3) { - snprintf(p->cmd_buf,CMD_BUFSIZE,"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",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",p->cmd_buf,rsp_txt); - close_f(stream); - return STREAM_ERROR; - } - - // Set the transfer type - resp = FtpSendCmd("TYPE I",p,rsp_txt); - if(resp != 2) { - mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command 'TYPE I' failed: %s\n",rsp_txt); - close_f(stream); - return STREAM_ERROR; - } - - // Get the filesize - snprintf(p->cmd_buf,CMD_BUFSIZE,"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",p->cmd_buf,rsp_txt); - } else { - int dummy; - sscanf(rsp_txt,"%d %"SCNd64,&dummy,&len); - } - - if(len > 0) { - stream->seek = seek; - stream->end_pos = len; - } - - // The data connection is really opened only at the first - // read/seek. This must be done when the cache is used - // because the connection would stay open in the main process, - // preventing correct abort with many servers. - stream->fd = -1; - stream->priv = p; - stream->fill_buffer = fill_buffer; - stream->close = close_f; - stream->type = STREAMTYPE_STREAM; - - return STREAM_OK; -} - -const stream_info_t stream_info_ftp = { - "File Transfer Protocol", - "ftp", - "Albeu", - "reuse a bit of code from ftplib written by Thomas Pfau", - open_f, - { "ftp", NULL }, - &stream_opts, - 1 // Urls are an option string -}; |