]> granicus.if.org Git - curl/commitdiff
Curl_GetFTPResponse() is rewritten to read all incoming data in large
authorDaniel Stenberg <daniel@haxx.se>
Thu, 26 Apr 2001 10:29:24 +0000 (10:29 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 26 Apr 2001 10:29:24 +0000 (10:29 +0000)
chunks, which makes it a lot faster and will make ftps work better...

lib/ftp.c

index 43c53a859e179d0b4491cbe12a1f7745b79978df..e634fa6ab6dc1de6ed0c68d17852069f4d02cfde 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -147,6 +147,165 @@ static CURLcode AllowServerConnect(struct UrlData *data,
 #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
                        isdigit((int)line[2]) && (' ' == line[3]))
 
+
+int Curl_GetFTPResponse(int sockfd,
+                        char *buf,
+                        struct connectdata *conn,
+                        int *ftpcode)
+{
+  /* Brand new implementation.
+   * We cannot read just one byte per read() and then go back to select()
+   * as it seems that the OpenSSL read() stuff doesn't grok that properly.
+   *
+   * Alas, read as much as possible, split up into lines, use the ending
+   * line in a response or continue reading.
+   */
+
+  int nread;   /* total size read */
+  int perline; /* count bytes per line */
+  bool keepon=TRUE;
+  ssize_t gotbytes;
+  char *ptr;
+  int timeout = 3600; /* default timeout in seconds */
+  struct timeval interval;
+  fd_set rkeepfd;
+  fd_set readfd;
+  struct UrlData *data = conn->data;
+  char *line_start;
+  int code;
+
+#define SELECT_OK      0
+#define SELECT_ERROR   1
+#define SELECT_TIMEOUT 2
+  int error = SELECT_OK;
+
+  if(ftpcode)
+    *ftpcode=0; /* 0 for errors */
+
+  if(data->timeout) {
+    /* if timeout is requested, find out how much remaining time we have */
+    timeout = data->timeout - /* timeout time */
+      (Curl_tvlong(Curl_tvnow()) - Curl_tvlong(conn->now)); /* spent time */
+    if(timeout <=0 ) {
+      failf(data, "Transfer aborted due to timeout");
+      return -SELECT_TIMEOUT; /* already too little time */
+    }
+  }
+
+  FD_ZERO (&readfd);           /* clear it */
+  FD_SET (sockfd, &readfd);     /* read socket */
+
+  /* get this in a backup variable to be able to restore it on each lap in the
+     select() loop */
+  rkeepfd = readfd;
+
+  ptr=buf;
+  line_start = buf;
+
+  nread=0;
+  perline=0;
+  keepon=TRUE;
+
+  while((nread<BUFSIZE) && (keepon && !error)) {
+    readfd = rkeepfd;             /* set every lap */
+    interval.tv_sec = timeout;
+    interval.tv_usec = 0;
+
+    switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
+    case -1: /* select() error, stop reading */
+      error = SELECT_ERROR;
+      failf(data, "Transfer aborted due to select() error");
+      break;
+    case 0: /* timeout */
+      error = SELECT_TIMEOUT;
+      failf(data, "Transfer aborted due to timeout");
+      break;
+    default:
+      /*
+       * This code previously didn't use the kerberos sec_read() code
+       * to read, but when we use Curl_read() it may do so. Do confirm
+       * that this is still ok and then remove this comment!
+       */
+      if(CURLE_OK != Curl_read(conn, sockfd, ptr, BUFSIZE-nread, &gotbytes))
+        keepon = FALSE;
+      else if(gotbytes <= 0) {
+        keepon = FALSE;
+        error = SELECT_ERROR;
+        failf(data, "Connection aborted");
+      }
+      else {
+        /* we got a whole chunk of data, which can be anything from one
+         * byte to a set of lines and possible just a piece of the last
+         * line */
+        int i;
+
+        nread += gotbytes;
+        for(i=0; i< gotbytes; ptr++, i++) {
+          perline++;
+          if(*ptr=='\n') {
+            /* a newline is CRLF in ftp-talk, so the CR is ignored as
+               the line isn't really terminated until the LF comes */
+
+            /* output debug output if that is requested */
+            if(data->bits.verbose) {
+              fputs("< ", data->err);
+              fwrite(line_start, 1, perline, data->err);
+              /* no need to output LF here, it is part of the data */
+            }
+
+            if(perline>3 && lastline(line_start)) {
+              /* This is the end of the last line, copy the last
+               * line to the start of the buffer and zero terminate,
+               * for old times sake (and krb4)! */
+              char *moo;
+              int i;
+              for(moo=line_start, i=0; moo<ptr; moo++, i++)
+                buf[i] = *moo;
+              moo[i]=0; /* zero terminate */
+              keepon=FALSE;
+              break;
+            }
+            perline=0; /* line starts over here */
+            line_start = ptr+1;
+          }
+        }
+      }
+      break;
+    } /* switch */
+  } /* while there's buffer left and loop is requested */
+
+  if(!error)
+    code = atoi(buf);
+
+#if KRB4
+  /* handle the security-oriented responses 6xx ***/
+  /* FIXME: some errorchecking perhaps... ***/
+  switch(code) {
+  case 631:
+    sec_read_msg(conn, buf, prot_safe);
+    break;
+  case 632:
+    sec_read_msg(conn, buf, prot_private);
+    break;
+  case 633:
+    sec_read_msg(conn, buf, prot_confidential);
+    break;
+  default:
+    /* normal ftp stuff we pass through! */
+    break;
+  }
+#endif
+
+  if(error)
+    return -error;
+
+  if(ftpcode)
+    *ftpcode=code; /* return the initial number like this */
+
+  return nread; /* total amount of bytes read */
+}
+
+#if 0
 /*
  * We allow the ftpcode pointer to be NULL if no reply integer is wanted
  */
@@ -157,6 +316,7 @@ int Curl_GetFTPResponse(int sockfd, char *buf,
 {
   int nread;
   ssize_t keepon=TRUE;
+  size_t got;
   char *ptr;
   int timeout = 3600; /* in seconds */
   struct timeval interval;
@@ -260,6 +420,7 @@ int Curl_GetFTPResponse(int sockfd, char *buf,
 
   return nread;
 }
+#endif
 
 /* -- who are we? -- */
 char *Curl_getmyhost(char *buf, int buf_size)
@@ -837,7 +998,8 @@ CURLcode _ftp(struct connectdata *conn)
        }
        ftpsendf(conn->firstsocket, conn, "%s |%d|%s|%s|", *modep, eprtaf,
            portmsgbuf, tmp);
-      } else if (strcmp(*modep, "LPRT") == 0 || strcmp(*modep, "PORT") == 0) {
+      } else if (strcmp(*modep, "LPRT") == 0 ||
+                 strcmp(*modep, "PORT") == 0) {
        int i;
 
         if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
@@ -849,7 +1011,7 @@ CURLcode _ftp(struct connectdata *conn)
         if (strcmp(*modep, "LPRT") == 0) {
          snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
          if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) {
-           goto again;
+           continue;
          }
        }
        for (i = 0; i < alen; i++) {
@@ -858,18 +1020,18 @@ CURLcode _ftp(struct connectdata *conn)
          else
            snprintf(tmp, sizeof(tmp), "%u", ap[i]);
          if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) {
-           goto again;
+           continue;
          }
        }
         if (strcmp(*modep, "LPRT") == 0) {
          snprintf(tmp, sizeof(tmp), ",%d", plen);
          if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
-           goto again;
+           continue;
        }
        for (i = 0; i < plen; i++) {
          snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
          if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) {
-           goto again;
+            continue;
          }
        }
        ftpsendf(conn->firstsocket, conn, "%s %s", *modep, portmsgbuf);