Beispiel #1
0
static int seek(stream_t *s,off_t newpos) {
  struct stream_priv_s* p = s->priv;
  int resp;
  char rsp_txt[256];

  if(s->pos > s->end_pos) {
    s->eof=1;
    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 = 0;
    
    // 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);
    send(p->handle,pre_cmd+1,sizeof(pre_cmd)-1,0);
    
    //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);
      s->eof = 1;
      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);
}
Beispiel #2
0
/*
 * FtpClose - close a data connection
 */
GLOBALDEF int FtpClose(netbuf *nData)
{
	netbuf *ctrl;
	switch (nData->dir)
	{
		case FTPLIB_WRITE:
			/* potential problem - if buffer flush fails, how to notify user? */
			if (nData->buf != NULL)
				writeline(NULL, 0, nData);
		case FTPLIB_READ:
			if (nData->buf)
				free(nData->buf);
			shutdown(nData->handle,2);
			net_close(nData->handle);
			ctrl = nData->ctrl;
			free(nData);
			if (ctrl)
			{
				ctrl->data = NULL;
				return(readresp('2', ctrl));
			}
			return 1;
		case FTPLIB_CONTROL:
			if (nData->data)
			{
				nData->ctrl = NULL;
				FtpClose(nData);
			}
			net_close(nData->handle);
			free(nData);
			return 0;
	}
	return 1;
}
Beispiel #3
0
/*
 * FtpAcceptConnection - accept connection from server
 *
 * return 1 if successful, 0 otherwise
 */
static int FtpAcceptConnection (netbuf *nData, netbuf *nControl) {
    int sData;
    struct sockaddr addr;
    unsigned int l;
    int i;
    struct timeval tv;
    fd_set mask;
    int rv;

    FD_ZERO(&mask);
    FD_SET(nControl->handle, &mask);
    FD_SET(nData->handle, &mask);
    tv.tv_usec = 0;
    tv.tv_sec = ACCEPT_TIMEOUT;
    i = nControl->handle;
    if (i < nData->handle)
        i = nData->handle;
    i = select(i + 1, &mask, NULL, NULL, &tv);
    if (i == -1) {
        strncpy(nControl->response, strerror(errno),
            sizeof (nControl->response));
        net_close(nData->handle);
        nData->handle = 0;
        rv = 0;
    }
    else if (i == 0) {
        strcpy(nControl->response, "timed out waiting for connection");
        net_close(nData->handle);
        nData->handle = 0;
        rv = 0;
    }
    else {
        if (FD_ISSET(nData->handle, &mask)) {
            l = sizeof (addr);
            sData = accept(nData->handle, &addr, &l);
            i = errno;
            net_close(nData->handle);
            if (sData > 0) {
                rv = 1;
                nData->handle = sData;
            }
            else {
                strncpy(nControl->response, strerror(i),
                    sizeof (nControl->response));
                nData->handle = 0;
                rv = 0;
            }
        }
        else if (FD_ISSET(nControl->handle, &mask)) {
            net_close(nData->handle);
            nData->handle = 0;
            readresp('2', nControl);
            rv = 0;
        }
    }
    return rv;
}
Beispiel #4
0
/*
 * Ftp_Send - send a command and wait for expected response
 *
 * return 1 if proper response received, 0 otherwise
 */
int Ftp_Send(const char *cmd, char expresp, netbuf *nControl)
{
    char buf[256];
    if (nControl->dir != FTP_CONTROL)
	return 0;
    if (debug_lib > 2)
		fprintf(stderr,"%s\n",cmd);
    sprintf(buf,"%s\r\n",cmd);
	if (netwrite(nControl->handle,buf,strlen(buf), 0) <= 0)
		return 0;
    return readresp(expresp, nControl);
}
Beispiel #5
0
/*
 * FtpSendCmd - send a command and wait for expected response
 *
 * return 1 if proper response received, 0 otherwise
 */
static int FtpSendCmd (const char *cmd, char expresp, netbuf *nControl) {
    char buf[256];
    if (nControl->dir != FTPLIB_CONTROL)
        return 0;
    if (ftplib_debug > 2)
        fprintf(stderr, "%s\n", cmd);
    if ((strlen(cmd) + 3) > sizeof (buf))
        return 0;
    sprintf(buf, "%s\r\n", cmd);
    if (net_write(nControl->handle, buf, strlen(buf)) <= 0) {
        perror("write");
        return 0;
    }
    return readresp(expresp, nControl);
}
Beispiel #6
0
/*
 * FtpClose - close a data connection
 */
GLOBALDEF int FtpClose(netbuf *nData)
{
    netbuf *ctrl;
    if (nData->dir == FTPLIB_WRITE)
    {
    if (nData->buf != NULL)
        writeline(NULL, 0, nData);
    }
    else if (nData->dir != FTPLIB_READ)
    return 0;
    if (nData->buf)
        free(nData->buf);
    shutdown(nData->handle,2);
    net_close(nData->handle);
    ctrl = nData->ctrl;
    free(nData);
    if (ctrl)
        return(readresp('2', ctrl));
    return 1;
}
Beispiel #7
0
/*
 * Ftp_Connect - connect to remote server
 *
 * return 1 if connected, 0 if not
 */
int Ftp_Connect(const char *host, int port, netbuf **nControl)
{
	int		socket_d = 0;
    netbuf	*ctrl;

    socket_d = Socket_Connect(host, port);
	if (socket_d > 0)
	{
		// allocate and fill in netbuf structure

		ctrl = calloc(1,sizeof(netbuf));
		if (ctrl == NULL)
		{

			Socket_close(socket_d);
			return 0;
		}
		ctrl->buf = malloc(FTP_BUFSIZ);
		if (ctrl->buf == NULL)
		{

			Socket_close(socket_d);
			free(ctrl);
			return 0;
		}
		ctrl->handle = socket_d;
		ctrl->dir = FTP_CONTROL;
		if (readresp('2', ctrl) == 0)
		{

			Socket_close(socket_d);
			free(ctrl->buf);
			free(ctrl);
			return 0;
		}
		*nControl = ctrl;
		return 1;
	}
	else
		return 0;
}
Beispiel #8
0
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,0);

    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);
}
Beispiel #9
0
/*
 * FtpConnect - connect to remote server
 *
 * return 1 if connected, 0 if not
 */
GLOBALDEF int FtpConnect(const char *host, netbuf **nControl)
{
	int sControl;
	struct sockaddr_in sin;
	struct hostent *phe;
	struct servent *pse;
	int on=1;
	netbuf *ctrl;
	char *lhost;
	char *pnum;

	memset(&sin,0,sizeof(sin));
	sin.sin_family = AF_INET;
	lhost = strdup(host);
	pnum = strchr(lhost,':');
	if (pnum == NULL)
	{
#if defined(VMS)
		sin.sin_port = htons(21);
#else
		if ((pse = getservbyname("ftp","tcp")) == NULL)
		{
			perror("getservbyname");
			return 0;
		}
		sin.sin_port = pse->s_port;
#endif
	}
	else
	{
		*pnum++ = '\0';
		if (isdigit(*pnum))
			sin.sin_port = htons(atoi(pnum));
		else
		{
			pse = getservbyname(pnum,"tcp");
			if(pse == NULL) {
				perror("getservbyname");
				return 0;
			}
			sin.sin_port = pse->s_port;
		}
	}
	if ((sin.sin_addr.s_addr = inet_addr(lhost)) == -1)
	{
		if ((phe = gethostbyname(lhost)) == NULL)
		{
			perror("gethostbyname");
			return 0;
		}
		memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
	}
	free(lhost);
	sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sControl == -1)
	{
		perror("socket");
		return 0;
	}
	if (setsockopt(sControl,SOL_SOCKET,SO_REUSEADDR,
				SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
	{
		perror("setsockopt");
		net_close(sControl);
		return 0;
	}
	if (connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1)
	{
		perror("connect");
		net_close(sControl);
		return 0;
	}
	ctrl = calloc(1,sizeof(netbuf));
	if (ctrl == NULL)
	{
		perror("calloc");
		net_close(sControl);
		return 0;
	}
	ctrl->buf = malloc(FTPLIB_BUFSIZ);
	if (ctrl->buf == NULL)
	{
		perror("calloc");
		net_close(sControl);
		free(ctrl);
		return 0;
	}
	ctrl->handle = sControl;
	ctrl->dir = FTPLIB_CONTROL;
	ctrl->ctrl = NULL;
	ctrl->cmode = FTPLIB_DEFMODE;
	ctrl->idlecb = NULL;
	ctrl->idletime.tv_sec = ctrl->idletime.tv_usec = 0;
	ctrl->idlearg = NULL;
	ctrl->xfered = 0;
	ctrl->xfered1 = 0;
	ctrl->cbbytes = 0;
	if (readresp('2', ctrl) == 0)
	{
		net_close(sControl);
		free(ctrl->buf);
		free(ctrl);
		return 0;
	}
	*nControl = ctrl;
	return 1;
}
Beispiel #10
0
/*
 * Ftp_Xfer - issue a command and transfer data
 *
 * return SRL_SUCCESS if successful,  otherwise
 */
static short Ftp_Xfer(const char *path, Bytes_struct *inBuf,
	netbuf *nControl, int mode)
{
    int len = 0, totlen = 0, status = 0;
    char dbuf[FTP_BUFSIZ];
	struct ftpbuf *tail = NULL, *head = NULL;
	struct ftpbuf *curr;
    netbuf *nData;

    inBuf->num = 0;
	
    if (!Ftp_Access(path, mode, nControl, &nData))
		return SRL_TCP_CONNECTION_FAILED;
 
    while ((len = Ftp_Read(dbuf, FTP_BUFSIZ, nData)) > 0)
	{
		if (totlen == 0)
		{
			status = addFtpBuf(&head, dbuf, len);
			if (status == 0)
				return SRL_MEMORY_ERROR;
			tail = head;
			totlen = len;
		}
		else
		{		
			status = addFtpBuf(&(tail->next), dbuf, len); 
			if (status == 0)
				return SRL_MEMORY_ERROR;
			tail = tail->next; 
			totlen += len;
		}		
	}

	// Copy ftpData to inbuf->buf
	inBuf->data = (unsigned char *) calloc (1, totlen);
	if (inBuf->data == NULL)
	{
		// Could not allocate memory
		// Free fp & return 0
		freeFtpBuf(head);
		return SRL_SUCCESS;
	}

	inBuf->num = 0;
	len = 0;
	curr = head;
	while(curr != NULL)
	{
		memcpy(inBuf->data+len, curr->buf, curr->len);
		inBuf->num += curr->len;
		len = curr->len;
		curr = curr->next;
	}
    freeFtpBuf(head);
    Ftp_Socket_close(nData);

	if (readresp('2', nControl))
		return SRL_SUCCESS;
	else
		return SRL_FTP_ERROR;
}
Beispiel #11
0
/*
 * FtpConnect - connect to remote server
 *
 * return 1 if connected, 0 if not
 */
GLOBALDEF int FtpConnect(const char *host, netbuf **nControl)
{
    int sControl, stat, flags, oldflags;
    struct sockaddr_in sin;
    struct hostent *phe;
    struct servent *pse;
    int on=1;
    netbuf *ctrl;
    char *lhost;
    char *pnum;
    struct timeval tv;
    fd_set wr;

    memset(&sin,0,sizeof(sin));
    sin.sin_family = AF_INET;
    lhost = strdup(host);
    pnum = strchr(lhost,':');
    if (pnum == NULL)
      {
#if defined(VMS) || defined(ANDROID)
          sin.sin_port = htons(21);
#else
          if ((pse = getservbyname("ftp","tcp")) == NULL)
            {
                perror("getservbyname");
                return 0;
            }
          sin.sin_port = pse->s_port;
#endif
      }
    else
      {
          *pnum++ = '\0';
          if (isdigit(*pnum))
              sin.sin_port = htons(atoi(pnum));
          else
            {
                pse = getservbyname(pnum,"tcp");
                sin.sin_port = pse->s_port;
            }
      }
    if ((sin.sin_addr.s_addr = inet_addr(lhost)) == -1)
      {
          if ((phe = gethostbyname(lhost)) == NULL)
            {
                perror("gethostbyname");
                return 0;
            }

          memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);

      }
    free(lhost);

    sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sControl == -1)
      {
          perror("socket");
          return 0;
      }

    if ( setsockopt(sControl,SOL_SOCKET,SO_REUSEADDR,
                   SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
      {
          perror("setsockopt");
          net_close(sControl);
          return 0;
      }

#if defined(_WIN32)
	if (connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1)
	{
		perror("connect");
		net_close(sControl);
		return 0;
	}
#else
     //set nonblocking for connection timeout
    flags = fcntl( sControl, F_GETFL,0);
    oldflags=flags;
    fcntl( sControl, F_SETFL, O_NONBLOCK|flags);

    stat=connect( sControl, (struct sockaddr *)&sin, sizeof(sin));
    if (stat < 0) 
      { 
          if (errno != EWOULDBLOCK && errno != EINPROGRESS) 
            { 
                perror("connect");
                net_close(sControl);
                return 0;
            } 
      } 

    FD_ZERO(&wr); 
    FD_SET( sControl, &wr); 

    tv.tv_sec = ACCEPT_TIMEOUT;
    tv.tv_usec = 0; 

    stat = select(sControl+1, 0, &wr, 0, &tv);

    if (stat < 1)
      { 
            // time out has expired, 
            // or an error has ocurred
          perror("timeout");
          net_close(sControl);
          return 0;
      } 

    if (ftplib_debug > 1)
        printf("connected\n");

      //set original flags
    fcntl( sControl, F_SETFL, oldflags);
#endif

    ctrl = calloc(1,sizeof(netbuf));
    if (ctrl == NULL)
      {
          perror("calloc");
          net_close(sControl);
          return 0;
      }
    ctrl->buf = malloc(FTPLIB_BUFSIZ);
    if (ctrl->buf == NULL)
      {
          perror("calloc");
          net_close(sControl);
          free(ctrl);
          return 0;
      }
    ctrl->handle = sControl;
    ctrl->dir = FTPLIB_CONTROL;
    ctrl->ctrl = NULL;
    ctrl->cmode = FTPLIB_DEFMODE;
    ctrl->idlecb = NULL;
    ctrl->writercb = NULL;
    ctrl->idletime.tv_sec = ctrl->idletime.tv_usec = 0;
    ctrl->idlearg = NULL;
    ctrl->writerarg = NULL;
    ctrl->xfered = 0;
    ctrl->xfered1 = 0;
    ctrl->cbbytes = 0;
    if (readresp('2', ctrl) == 0)
      {
          net_close(sControl);
          free(ctrl->buf);
          free(ctrl);
          return 0;
      }
    *nControl = ctrl;
    return 1;
}
Beispiel #12
0
static int open_f(stream_t *stream,int mode, void* opts, int* file_format) {
  int len = 0,resp;
  struct stream_priv_s* p = (struct stream_priv_s*)opts;
  char str[256],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;
  }

  // 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;
  p->buf = malloc(BUFSIZE);

  if (readresp(p, NULL) == 0) {
    close_f(stream);
    m_struct_free(&stream_opts,opts);
    return STREAM_ERROR;
  }

  // Login
  snprintf(str,255,"USER %s",p->user);
  resp = FtpSendCmd(str,p,rsp_txt);

  // password needed
  if(resp == 3) {
    snprintf(str,255,"PASS %s",p->pass);
    resp = FtpSendCmd(str,p,rsp_txt);
    if(resp != 2) {
      mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,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);
    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(str,255,"SIZE %s",p->filename);
  resp = FtpSendCmd(str,p,rsp_txt);
  if(resp != 2) {
    mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
  } else {
    int dummy;
    sscanf(rsp_txt,"%d %d",&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;

  return STREAM_OK;
}