Commit 8333644c authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

moved the PORT and PASV code into separate smaller functions for readability

renamed all static ^_ftp_* functions to ^ftp_, prefixing with underscore is
not nice
parent 4d13b2cc
Loading
Loading
Loading
Loading
+555 −499
Original line number Diff line number Diff line
@@ -92,8 +92,8 @@
#endif

/* Local API functions */
static CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote);
static CURLcode _ftp_cwd(struct connectdata *conn, char *path);
static CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote);
static CURLcode ftp_cwd(struct connectdata *conn, char *path);

/* easy-to-use macro: */
#define ftpsendf Curl_ftpsendf
@@ -590,7 +590,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn)

  /* Send any post-transfer QUOTE strings? */
  if(data->set.postquote) {
    CURLcode result = _ftp_sendquote(conn, data->set.postquote);
    CURLcode result = ftp_sendquote(conn, data->set.postquote);
    return result;
  }

@@ -599,7 +599,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn)


static 
CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
{
  struct curl_slist *item;
  ssize_t            nread;
@@ -628,7 +628,7 @@ CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
}

static 
CURLcode _ftp_cwd(struct connectdata *conn, char *path)
CURLcode ftp_cwd(struct connectdata *conn, char *path)
{
  ssize_t nread;
  int     ftpcode;
@@ -648,7 +648,7 @@ CURLcode _ftp_cwd(struct connectdata *conn, char *path)
}

static
CURLcode _ftp_getfiletime(struct connectdata *conn, char *file)
CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
{
  CURLcode result=CURLE_OK;
  int ftpcode; /* for ftp status */
@@ -683,7 +683,7 @@ CURLcode _ftp_getfiletime(struct connectdata *conn, char *file)
  return  result;
}

static CURLcode _ftp_transfertype(struct connectdata *conn,
static CURLcode ftp_transfertype(struct connectdata *conn,
                                  bool ascii)
{
  struct SessionHandle *data = conn->data;
@@ -707,7 +707,7 @@ static CURLcode _ftp_transfertype(struct connectdata *conn,
}

static
CURLcode _ftp_getsize(struct connectdata *conn, char *file,
CURLcode ftp_getsize(struct connectdata *conn, char *file,
                      ssize_t *size)
{
  struct SessionHandle *data = conn->data;
@@ -741,12 +741,9 @@ CURLcode _ftp_getsize(struct connectdata *conn, char *file,
 */
static void
ftp_pasv_verbose(struct connectdata *conn,
#ifdef ENABLE_IPV6
                 struct addrinfo *newhost
#else
                 char *newhost /* ipv4 */
#endif
)
                 Curl_addrinfo *addr,
                 char *newhost, /* ascii version */
                 int port)
{
#ifndef ENABLE_IPV6
  /*****************************************************************
@@ -757,11 +754,10 @@ ftp_pasv_verbose(struct connectdata *conn,
  struct in_addr in;
  struct hostent * answer;

#if defined (HAVE_INET_NTOA_R)
#ifdef HAVE_INET_NTOA_R
  char ntoa_buf[64];
#endif
#ifndef ENABLE_IPV6
  struct sockaddr_in serv_addr;
  char hostent_buf[8192];
#endif

@@ -817,11 +813,11 @@ ftp_pasv_verbose(struct connectdata *conn,
  infof(conn->data, "Connecting to %s (%s) port %u\n",
        answer?answer->h_name:newhost,
#if defined(HAVE_INET_NTOA_R)
        inet_ntoa_r(in, ip_addr=ntoa_buf, sizeof(ntoa_buf)),
        inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
#else
        ip_addr = inet_ntoa(in),
        inet_ntoa(in),
#endif
        connectport);
        port);

#else
  /*****************************************************************
@@ -836,13 +832,13 @@ ftp_pasv_verbose(struct connectdata *conn,
#else
  const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
#endif
  if (getnameinfo(newhost->ai_addr, newhost->ai_addrlen,
  if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
                  nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), niflags)) {
    snprintf(nbuf, sizeof(nbuf), "?");
    snprintf(sbuf, sizeof(sbuf), "?");
  }
        
  if (getnameinfo(newhost->ai_addr, newhost->ai_addrlen,
  if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
                  hbuf, sizeof(hbuf), NULL, 0, 0)) {
    infof(conn->data, "Connecting to %s port %s\n", nbuf, sbuf);
  } 
@@ -850,104 +846,30 @@ ftp_pasv_verbose(struct connectdata *conn,
    infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf);
  }
#endif

}

/**********
 * PORT is the ftp client's way of telling the server that *WE* open a port
 * that we listen on an awaits the server to connect to. This is the opposite
 * of PASV.
 */

static
CURLcode _ftp(struct connectdata *conn)
CURLcode ftp_use_port(struct connectdata *conn)
{
  /* this is FTP and no proxy */
  ssize_t nread;
  CURLcode result;
  struct SessionHandle *data=conn->data;
  char *buf = data->state.buffer; /* this is our buffer */
  /* for the ftp PORT mode */
  int portsock=-1;
  /* the ftp struct is already inited in ftp_connect() */
  struct FTP *ftp = conn->proto.ftp;

  long *bytecountp = ftp->bytecountp;
  int ftpcode; /* for ftp status */

  /* Send any QUOTE strings? */
  if(data->set.quote) {
    if ((result = _ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
      return result;
  }
    
  /* This is a re-used connection. Since we change directory to where the
     transfer is taking place, we must now get back to the original dir
     where we ended up after login: */
  if (conn->bits.reuse) {
    if ((result = _ftp_cwd(conn, ftp->entrypath)) != CURLE_OK)
      return result;
  }

  /* change directory first! */
  if(ftp->dir && ftp->dir[0]) {
    if ((result = _ftp_cwd(conn, ftp->dir)) != CURLE_OK)
        return result;
  }

  /* Requested time of file? */
  if(data->set.get_filetime && ftp->file) {
    result = _ftp_getfiletime(conn, ftp->file);
    if(result)
      return result;
  }

  /* If we have selected NOBODY, it means that we only want file information.
     Which in FTP can't be much more than the file size! */
  if(data->set.no_body) {
    /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
       may not support it! It is however the only way we have to get a file's
       size! */
    ssize_t filesize;

    /* Some servers return different sizes for different modes, and thus we
       must set the proper type before we check the size */
    result = _ftp_transfertype(conn, data->set.ftp_ascii);
    if(result)
      return result;

    /* failing to get size is not a serious error */
    result = _ftp_getsize(conn, ftp->file, &filesize);

    if(CURLE_OK == result) {
      sprintf(buf, "Content-Length: %d\r\n", filesize);
      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
      if(result)
        return result;
    }

    /* If we asked for a time of the file and we actually got one as
       well, we "emulate" a HTTP-style header in our output. */

#ifdef HAVE_STRFTIME
    if(data->set.get_filetime && data->info.filetime) {
      struct tm *tm;
#ifdef HAVE_LOCALTIME_R
      struct tm buffer;
      tm = (struct tm *)localtime_r(&data->info.filetime, &buffer);
#else
      tm = localtime(&data->info.filetime);
#endif
      /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
      strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n",
               tm);
      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
      if(result)
        return result;
    }
#endif

    return CURLE_OK;
  }
  ssize_t nread;
  char *buf = data->state.buffer; /* this is our buffer */
  int ftpcode; /* receive FTP response codes in this */

  /* We have chosen to use the PORT command */
  if(data->set.ftp_use_port) {
#ifdef ENABLE_IPV6
  /******************************************************************
   *
   * Here's a piece of IPv6-specific code coming up
   *
   */

  struct addrinfo hints, *res, *ai;
  struct sockaddr_storage ss;
  socklen_t sslen;
@@ -1076,7 +998,8 @@ CURLcode _ftp(struct connectdata *conn)
      portmsgbuf[0] = '\0';
      if (strcmp(*modep, "LPRT") == 0) {
        snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
          if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) {
        if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
            sizeof(portmsgbuf)) {
          continue;
        }
      }
@@ -1087,7 +1010,8 @@ CURLcode _ftp(struct connectdata *conn)
        else
          snprintf(tmp, sizeof(tmp), "%u", ap[i]);
        
          if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) {
        if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
            sizeof(portmsgbuf)) {
          continue;
        }
      }
@@ -1102,7 +1026,8 @@ CURLcode _ftp(struct connectdata *conn)
      for (i = 0; i < plen; i++) {
        snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
        
          if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) {
        if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
            sizeof(portmsgbuf)) {
          continue;
        }
      }
@@ -1117,7 +1042,8 @@ CURLcode _ftp(struct connectdata *conn)
    if (ftpcode != 200) {
      failf(data, "Server does not grok %s", *modep);
      continue;
      } else
    }
    else
      break;
  }
  
@@ -1132,6 +1058,11 @@ CURLcode _ftp(struct connectdata *conn)
  conn->secondarysocket = portsock;
  
#else
  /******************************************************************
   *
   * Here's a piece of IPv4-specific code coming up
   *
   */
  struct sockaddr_in sa;
  struct hostent *h=NULL;
  char *hostdataptr=NULL;
@@ -1212,10 +1143,13 @@ CURLcode _ftp(struct connectdata *conn)
    return CURLE_FTP_PORT_FAILED;
  }
  {
#ifdef HAVE_INET_NTOA_R
    char ntoa_buf[64];
#endif
    struct in_addr in;
    unsigned short ip[5];
    (void) memcpy(&in.s_addr, *h->h_addr_list, sizeof (in.s_addr));
#if defined (HAVE_INET_NTOA_R)
#ifdef HAVE_INET_NTOA_R
    /* ignore the return code from inet_ntoa_r() as it is int or
       char * depending on system */
    inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf));
@@ -1239,9 +1173,26 @@ CURLcode _ftp(struct connectdata *conn)
    failf(data, "Server does not grok PORT, try without it!");
    return CURLE_FTP_PORT_FAILED;
  }
#endif /* ENABLE_IPV6 */
#endif /* end of ipv4-specific code */

  return CURLE_OK;
}
  else { /* we use the PASV command */

/**********
 * PASV is the ftp client's way of asking the server to open a second port
 * that we can connect to (for the data transfer). This is the opposite of
 * PORT.
 */

static
CURLcode ftp_use_pasv(struct connectdata *conn)
{
  struct SessionHandle *data = conn->data;
  ssize_t nread;
  char *buf = data->state.buffer; /* this is our buffer */
  int ftpcode; /* receive FTP response codes in this */
  CURLcode result;

#if 0
  /* no support for IPv6 passive mode yet */
  char *mode[] = { "EPSV", "LPSV", "PASV", NULL };
@@ -1276,10 +1227,10 @@ CURLcode _ftp(struct connectdata *conn)
    Curl_addrinfo *addr;
    char *hostdataptr=NULL;

#ifndef ENABLE_IPV6
      char *ip_addr;
#else
#ifdef ENABLE_IPV6
    struct addrinfo *ai;
#else
    struct sockaddr_in serv_addr;
#endif
    char *str=buf;

@@ -1349,7 +1300,7 @@ CURLcode _ftp(struct connectdata *conn)

      if(data->set.verbose)
        /* this just dumps information about this second connection */
          ftp_pasv_verbose(conn, ai);
        ftp_pasv_verbose(conn, ai, newhost, 0 /* port not really known */);
      break;
    }

@@ -1369,7 +1320,7 @@ CURLcode _ftp(struct connectdata *conn)

    if(data->set.verbose)
      /* this just dumps information about this second connection */
        ftp_pasv_verbose(conn, newhost);
      ftp_pasv_verbose(conn, addr, newhost, connectport);
	
    if(hostdataptr)
      free(hostdataptr);
@@ -1403,17 +1354,122 @@ CURLcode _ftp(struct connectdata *conn)
      if(CURLE_OK != result)
        return result;
    }
    } else {
  }
  else
    return CURLE_FTP_CANT_RECONNECT;

  return CURLE_OK;
}


static
CURLcode ftp_perform(struct connectdata *conn)
{
  /* this is FTP and no proxy */
  ssize_t nread;
  CURLcode result;
  struct SessionHandle *data=conn->data;
  char *buf = data->state.buffer; /* this is our buffer */

  /* the ftp struct is already inited in ftp_connect() */
  struct FTP *ftp = conn->proto.ftp;

  long *bytecountp = ftp->bytecountp;
  int ftpcode; /* for ftp status */

  /* Send any QUOTE strings? */
  if(data->set.quote) {
    if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
      return result;
  }
    
  /* This is a re-used connection. Since we change directory to where the
     transfer is taking place, we must now get back to the original dir
     where we ended up after login: */
  if (conn->bits.reuse) {
    if ((result = ftp_cwd(conn, ftp->entrypath)) != CURLE_OK)
      return result;
  }

  /* change directory first! */
  if(ftp->dir && ftp->dir[0]) {
    if ((result = ftp_cwd(conn, ftp->dir)) != CURLE_OK)
        return result;
  }

  /* Requested time of file? */
  if(data->set.get_filetime && ftp->file) {
    result = ftp_getfiletime(conn, ftp->file);
    if(result)
      return result;
  }

  /* If we have selected NOBODY, it means that we only want file information.
     Which in FTP can't be much more than the file size! */
  if(data->set.no_body) {
    /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
       may not support it! It is however the only way we have to get a file's
       size! */
    ssize_t filesize;

    /* Some servers return different sizes for different modes, and thus we
       must set the proper type before we check the size */
    result = ftp_transfertype(conn, data->set.ftp_ascii);
    if(result)
      return result;

    /* failing to get size is not a serious error */
    result = ftp_getsize(conn, ftp->file, &filesize);

    if(CURLE_OK == result) {
      sprintf(buf, "Content-Length: %d\r\n", filesize);
      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
      if(result)
        return result;
    }
  /* we have the (new) data connection ready */

    /* If we asked for a time of the file and we actually got one as
       well, we "emulate" a HTTP-style header in our output. */

#ifdef HAVE_STRFTIME
    if(data->set.get_filetime && data->info.filetime) {
      struct tm *tm;
#ifdef HAVE_LOCALTIME_R
      struct tm buffer;
      tm = (struct tm *)localtime_r(&data->info.filetime, &buffer);
#else
      tm = localtime(&data->info.filetime);
#endif
      /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
      strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n",
               tm);
      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
      if(result)
        return result;
    }
#endif

    return CURLE_OK;
  }

  /* Get us a second connection up and connected */
  if(data->set.ftp_use_port)
    /* We have chosen to use the PORT command */
    result = ftp_use_port(conn);
  else
    /* We have chosen (this is default) to use the PASV command */
    result = ftp_use_pasv(conn);

  if(result)
    return result;

  /* we have the data connection ready */
  infof(data, "Connected the data stream!\n");

  if(data->set.upload) {

    /* Set type to binary (unless specified ASCII) */
    result = _ftp_transfertype(conn, data->set.ftp_ascii);
    result = ftp_transfertype(conn, data->set.ftp_ascii);
    if(result)
      return result;

@@ -1435,7 +1491,7 @@ CURLcode _ftp(struct connectdata *conn)
        /* we could've got a specified offset from the command line,
           but now we know we didn't */

        if(CURLE_OK != _ftp_getsize(conn, ftp->file, &conn->resume_from)) {
        if(CURLE_OK != ftp_getsize(conn, ftp->file, &conn->resume_from)) {
          failf(data, "Couldn't get remote file size");
          return CURLE_FTP_COULDNT_GET_SIZE;
        }
@@ -1510,7 +1566,7 @@ CURLcode _ftp(struct connectdata *conn)

    if(data->set.ftp_use_port) {
      /* PORT means we are now awaiting the server to connect to us. */
      result = AllowServerConnect(data, conn, portsock);
      result = AllowServerConnect(data, conn, conn->secondarysocket);
      if( result )
        return result;
    }
@@ -1578,7 +1634,7 @@ CURLcode _ftp(struct connectdata *conn)
      dirlist = TRUE;

      /* Set type to ASCII */
      result = _ftp_transfertype(conn, TRUE /* ASCII enforced */);
      result = ftp_transfertype(conn, TRUE /* ASCII enforced */);
      if(result)
        return result;

@@ -1592,7 +1648,7 @@ CURLcode _ftp(struct connectdata *conn)
    }
    else {
      /* Set type to binary (unless specified ASCII) */
      result = _ftp_transfertype(conn, data->set.ftp_ascii);
      result = ftp_transfertype(conn, data->set.ftp_ascii);
      if(result)
        return result;

@@ -1605,7 +1661,7 @@ CURLcode _ftp(struct connectdata *conn)
         * the best way to know if we're trying to resume beyond the EOF.  */
        int foundsize=-1;
        
        result = _ftp_getsize(conn, ftp->file, &foundsize);
        result = ftp_getsize(conn, ftp->file, &foundsize);

        if(CURLE_OK != result) {
          infof(data, "ftp server doesn't support SIZE\n");
@@ -1736,7 +1792,7 @@ CURLcode _ftp(struct connectdata *conn)
        size = downloadsize;

      if(data->set.ftp_use_port) {
        result = AllowServerConnect(data, conn, portsock);
        result = AllowServerConnect(data, conn, conn->secondarysocket);
        if( result )
          return result;
      }
@@ -1813,7 +1869,7 @@ CURLcode Curl_ftp(struct connectdata *conn)
  else
    ftp->dir = NULL;

  retcode = _ftp(conn);
  retcode = ftp_perform(conn);

  /* clean up here, success or error doesn't matter */
  if(ftp->file)