]> granicus.if.org Git - curl/commitdiff
Fixed a problem where telnet data would be lost if an EWOULDBLOCK
authorDan Fandrich <dan@coneharvesters.com>
Tue, 3 Jun 2008 18:03:11 +0000 (18:03 +0000)
committerDan Fandrich <dan@coneharvesters.com>
Tue, 3 Jun 2008 18:03:11 +0000 (18:03 +0000)
condition were encountered.

CHANGES
RELEASE-NOTES
lib/telnet.c

diff --git a/CHANGES b/CHANGES
index 868e6ce0a47e2602683afc78ed0863aa4cbb45b9..8eddff09e92c8a4e424ca4e8164e03e8aaf306db 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -7,6 +7,10 @@
                                   Changelog
 
 
+Daniel Fandrich (3 Jun 2008)
+- Fixed a problem where telnet data would be lost if an EWOULDBLOCK
+  condition were encountered.
+
 Marty Kuhrt (1 Jun 2008)
 - Updated main.c to return CURLE_OK if PARAM_HELP_REQUESTED was returned
   from getparameter instead of CURLE_FAILED_INIT.  No point in returning
index 117a6f8c68565e00de939cdd6ea3d5f22b085dc3..3e6cbf817071da9b16c7290ac7e68e7436b77806 100644 (file)
@@ -40,6 +40,7 @@ This release includes the following bugfixes:
  o follow redirect with only a new query string
  o SCP and SFTP memory leaks on aborted transfers
  o curl_multi_socket() and HTTP pipelining transfer stalls
+ o lost telnet data on an EWOULDBLOCK condition
 
 This release includes the following known bugs:
 
index a531e6743f3886c5c55bbef4d73708d82aa7da4c..c446589149343c84df63b35ad75fc2b8db695245 100644 (file)
@@ -1117,6 +1117,46 @@ void telrcv(struct connectdata *conn,
   bufferflush();
 }
 
+/* Escape and send a telnet data block */
+/* TODO: write large chunks of data instead of one byte at a time */
+static CURLcode send_telnet_data(struct connectdata *conn,
+                                char *buffer, ssize_t nread)
+{
+  unsigned char outbuf[2];
+  ssize_t bytes_written, total_written;
+  int out_count;
+  CURLcode rc = CURLE_OK;
+
+  while(rc == CURLE_OK && nread--) {
+    outbuf[0] = *buffer++;
+    out_count = 1;
+    if(outbuf[0] == CURL_IAC)
+      outbuf[out_count++] = CURL_IAC;
+
+    total_written = 0;
+    do {
+      /* Make sure socket is writable to avoid EWOULDBLOCK condition */
+      struct pollfd pfd[1];
+      pfd[0].fd = conn->sock[FIRSTSOCKET];
+      pfd[0].events = POLLOUT;
+      switch (Curl_poll(pfd, 1, -1)) {
+       case -1:                    /* error, abort writing */
+       case 0:                     /* timeout (will never happen) */
+         rc = CURLE_SEND_ERROR;
+         break;
+       default:                    /* write! */
+         bytes_written = 0;
+         rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written,
+                         out_count-total_written, &bytes_written);
+         total_written += bytes_written;
+         break;
+      }
+    /* handle partial write */
+    } while (rc == CURLE_OK && total_written < out_count);
+  }
+  return rc;
+}
+
 static CURLcode telnet_done(struct connectdata *conn,
                                  CURLcode status, bool premature)
 {
@@ -1270,63 +1310,45 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
     switch(waitret) {
     case WAIT_TIMEOUT:
     {
-      unsigned char outbuf[2];
-      int out_count = 0;
-      ssize_t bytes_written;
-      char *buffer = buf;
-
       while(1) {
         if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
           keepon = FALSE;
+         code = CURLE_READ_ERROR;
           break;
         }
-        nread = readfile_read;
 
-        if(!nread)
+        if(!readfile_read)
           break;
 
         if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
                      &readfile_read, NULL)) {
           keepon = FALSE;
+         code = CURLE_READ_ERROR;
           break;
         }
-        nread = readfile_read;
 
-        while(nread--) {
-          outbuf[0] = *buffer++;
-          out_count = 1;
-          if(outbuf[0] == CURL_IAC)
-            outbuf[out_count++] = CURL_IAC;
-
-          Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
-                     out_count, &bytes_written);
-        }
+        code = send_telnet_data(conn, buf, readfile_read);
+       if(code) {
+          keepon = FALSE;
+         break;
+       }
       }
     }
     break;
 
     case WAIT_OBJECT_0 + 1:
     {
-      unsigned char outbuf[2];
-      int out_count = 0;
-      ssize_t bytes_written;
-      char *buffer = buf;
-
       if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
                    &readfile_read, NULL)) {
         keepon = FALSE;
+       code = CURLE_READ_ERROR;
         break;
       }
-      nread = readfile_read;
 
-      while(nread--) {
-        outbuf[0] = *buffer++;
-        out_count = 1;
-        if(outbuf[0] == CURL_IAC)
-          outbuf[out_count++] = CURL_IAC;
-
-        Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
-                   out_count, &bytes_written);
+      code = send_telnet_data(conn, buf, readfile_read);
+      if(code) {
+       keepon = FALSE;
+       break;
       }
     }
     break;
@@ -1389,22 +1411,12 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
       break;
     default:                    /* read! */
       if(pfd[1].revents & POLLIN) { /* read from stdin */
-        unsigned char outbuf[2];
-        int out_count = 0;
-        ssize_t bytes_written;
-        char *buffer = buf;
-
         nread = read(0, buf, 255);
-
-        while(nread--) {
-          outbuf[0] = *buffer++;
-          out_count = 1;
-          if(outbuf[0] == CURL_IAC)
-            outbuf[out_count++] = CURL_IAC;
-
-          Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
-                     out_count, &bytes_written);
-        }
+        code = send_telnet_data(conn, buf, nread);
+       if(code) {
+          keepon = FALSE;
+         break;
+       }
       }
 
       if(pfd[0].revents & POLLIN) {