embeddedmz / ftpclient-cpp

C++ client for making FTP requests
MIT License
211 stars 67 forks source link

CFTPClient::Info will report CURLE_WRITE_ERROR after use many times #48

Closed graceon closed 1 year ago

graceon commented 1 year ago
for (int i = 0;i < 10000; i++)
{
    CFTPClient::FileInfo ResFileInfo = { 0, 0.0 };
    bool bOkInfo = FTPClient.Info("/a.txt", ResFileInfo);
}

when i = 47 logger say [FTPClient][Error] Unable to get file /a.txt's info (Error = 23 | Failed writing received data to disk/application). so i modify CFTPClient::Info add 3 line and i seem work ok; ![Uploading image.png…]()

graceon commented 1 year ago

seeing //my add start

bool CFTPClient::Info(const std::string &strRemoteFile, struct FileInfo &oFileInfo) const {
   if (strRemoteFile.empty()) return false;

   if (!m_pCurlSession) {
      if (m_eSettingsFlags & ENABLE_LOG) m_oLog(LOG_ERROR_CURL_NOT_INIT_MSG);

      return false;
   }
   // Reset is mandatory to avoid bad surprises
   curl_easy_reset(m_pCurlSession);

   bool bRes = false;

   oFileInfo.tFileMTime = 0;
   oFileInfo.dFileSize  = 0.0;

   curl_easy_setopt(m_pCurlSession, CURLOPT_URL, ParseURL(strRemoteFile).c_str());

   /* No download if the file */
   curl_easy_setopt(m_pCurlSession, CURLOPT_NOBODY, 1L);

   /* Ask for filetime */
   curl_easy_setopt(m_pCurlSession, CURLOPT_FILETIME, 1L);

   /* No header output: TODO 14.1 http-style HEAD output for ftp */
   curl_easy_setopt(m_pCurlSession, CURLOPT_HEADERFUNCTION, ThrowAwayCallback);
   curl_easy_setopt(m_pCurlSession, CURLOPT_HEADER, 0L);
//my add start
   curl_easy_setopt(m_pCurlSession, CURLOPT_WRITEFUNCTION, WriteInStringCallback);
   std::string strList;
   curl_easy_setopt(m_pCurlSession, CURLOPT_WRITEDATA, &strList);
//my add end
   CURLcode res = Perform();

   if (CURLE_OK == res) {
      long lFileTime = -1;

      res = curl_easy_getinfo(m_pCurlSession, CURLINFO_FILETIME, &lFileTime);
      if (CURLE_OK == res && lFileTime >= 0) {
         oFileInfo.tFileMTime = static_cast<time_t>(lFileTime);
         bRes                 = true;
      }

      res = curl_easy_getinfo(m_pCurlSession, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &oFileInfo.dFileSize);
      if (CURLE_OK != res || oFileInfo.dFileSize < 0.0) {
         bRes = false;
      }
   } else if (m_eSettingsFlags & ENABLE_LOG && res != CURLE_REMOTE_FILE_NOT_FOUND)
      m_oLog(StringFormat(LOG_ERROR_CURL_FILETIME_FORMAT, strRemoteFile.c_str(), res, curl_easy_strerror(res)));

   return bRes;
}
embeddedmz commented 1 year ago

With Cerberus FTP Server (FTP) and Rebex Tiny SFTP Server (SFTP) I don't have any issue running a loop of 10000 iterations.

I think it's a problem with the FTP server. For example, I don't use the FileZilla server to run unit tests because some tests (with loops) can fail on some runs due to things like timeouts or how the server is coded.

Recall a method if it returns "false" after waiting a certain period of time (i.e. implement a retry mechanism).

graceon commented 1 year ago

thanks for your advice yes i use FileZilla but how to explain when i add that code.it works perfectly than before

//my add start
   curl_easy_setopt(m_pCurlSession, CURLOPT_WRITEFUNCTION, WriteInStringCallback);
   std::string strList;
   curl_easy_setopt(m_pCurlSession, CURLOPT_WRITEDATA, &strList);
//my add end
embeddedmz commented 1 year ago

I think it creates a latency (in libcurl) that allows FileZilla to be responsive.

graceon commented 1 year ago

thanks