]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
ftp: flush pingpong before response
authorStefan Eissing <stefan@eissing.org>
Thu, 8 Aug 2024 11:12:53 +0000 (13:12 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 8 Aug 2024 15:52:25 +0000 (17:52 +0200)
Fix FTP protocol to flush the pingpong's send buffer before receiving a
response from the server, as it may never come otherwise.

Fixes FTP/FTPS tests with `CURL_DBG_SOCK_WBLOCK=90` set.

Closes #14452

lib/ftp.c
lib/pingpong.c
lib/pingpong.h

index 2f5748df7f861126ed98c6cae9c45a2a96be156a..9b2db627068a763e2a3651dfc8439db37c6d9d2a 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -819,6 +819,8 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
   int cache_skip = 0;
   int value_to_be_ignored = 0;
 
+  CURL_TRC_FTP(data, "getFTPResponse start");
+
   if(ftpcode)
     *ftpcode = 0; /* 0 for errors */
   else
@@ -864,21 +866,27 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
        */
     }
     else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) {
-      switch(SOCKET_READABLE(sockfd, interval_ms)) {
-      case -1: /* select() error, stop reading */
+      curl_socket_t wsock = Curl_pp_needs_flush(data, pp)?
+                            sockfd : CURL_SOCKET_BAD;
+      int ev = Curl_socket_check(sockfd, CURL_SOCKET_BAD, wsock, interval_ms);
+      if(ev < 0) {
         failf(data, "FTP response aborted due to select/poll error: %d",
               SOCKERRNO);
         return CURLE_RECV_ERROR;
-
-      case 0: /* timeout */
+      }
+      else if(ev == 0) {
         if(Curl_pgrsUpdate(data))
           return CURLE_ABORTED_BY_CALLBACK;
         continue; /* just continue in our loop for the timeout duration */
+      }
+    }
 
-      default: /* for clarity */
+    if(Curl_pp_needs_flush(data, pp)) {
+      result = Curl_pp_flushsend(data, pp);
+      if(result)
         break;
-      }
     }
+
     result = ftp_readresp(data, FIRSTSOCKET, pp, ftpcode, &nread);
     if(result)
       break;
@@ -897,6 +905,8 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
   } /* while there is buffer left and loop is requested */
 
   pp->pending_resp = FALSE;
+  CURL_TRC_FTP(data, "getFTPResponse -> result=%d, nread=%zd, ftpcode=%d",
+               result, *nreadp, *ftpcode);
 
   return result;
 }
index bf4f95763b424964eee9f27f4aa6b4fd395b9465..f31d1256f5c5af75516e705958d2d4148848cff5 100644 (file)
@@ -395,6 +395,13 @@ int Curl_pp_getsock(struct Curl_easy *data,
   return GETSOCK_READSOCK(0);
 }
 
+bool Curl_pp_needs_flush(struct Curl_easy *data,
+                         struct pingpong *pp)
+{
+  (void)data;
+  return pp->sendleft > 0;
+}
+
 CURLcode Curl_pp_flushsend(struct Curl_easy *data,
                            struct pingpong *pp)
 {
@@ -402,6 +409,9 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data,
   size_t written;
   CURLcode result;
 
+  if(!Curl_pp_needs_flush(data, pp))
+    return CURLE_OK;
+
   result = Curl_conn_send(data, FIRSTSOCKET,
                           pp->sendthis + pp->sendsize - pp->sendleft,
                           pp->sendleft, FALSE, &written);
index 62f2467fc87d91168818ac74e7a2e8cab855bbe2..72239ff05913d5f0275ce39f6a352cc8b2dcdb5a 100644 (file)
@@ -137,6 +137,8 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
                           int *code, /* return the server code if done */
                           size_t *size); /* size of the response */
 
+bool Curl_pp_needs_flush(struct Curl_easy *data,
+                         struct pingpong *pp);
 
 CURLcode Curl_pp_flushsend(struct Curl_easy *data,
                            struct pingpong *pp);