Hello all. I'm relatively new to libcurl C++, and I have been hopelessly stuck.
Bit of a background for this app. It is very legacy, having been made in the early 2000s. LPSTRs abound. It looks in FTPs for files from suppliers (who have an SFTP they interact with and a script grabs files from that and puts them on the FTP) and it processes them and sends the orders to our warehouse. We have a security item to cut out the FTP, which means making a C/C++ program interact with SFTPs directly. That is a long story short.
To that end, we implemented libcurl C++. It works with SFTPs that are through our b2b2 domain, but not with SFTPs that interact with ftp2 domains. Unfortunately, we are also being forced to migrate all the b2b2 SFTPs to our ftp2 domain.
The error is CURLE_FAILED_INIT, and CURLE_ERRORBUFFER further expands that to "Failure establishing ssh session: -43, Failed getting banner". I assume it does not mean Bruce Banner. I have Googled so much I have nightmares and nothing seems to work, like retries and CURLOPT_SSL_VERIFYHOST being 0L. I contacted our networking team and they confirmed the issue is NOT on their end. Same story with the team that creates and manages the SFTPs. I have stumped a lot of people with this.
The code I have follows:
struct SftpConnectionInfo {
std::string strUsername;
std::string strPassword;
std::string strServerPath;
};
struct GetDirListData {
std::string strFilePrefix;
std::vector<std::string> strMatchedFilenames;
};
static size_t GetDirListCallbackFunction(char* izard, size_t size, size_t nmemb, GetDirListData* dirListData)
{
size_t totalSize = size * nmemb;
std::string strFilename = izard;
const size_t underscorePos = strFilename.find("_");
std::string strFilePrefix = dirListData->strFilePrefix;
std::string strPrefixOnFile = (strFilename.substr(0, underscorePos));
std::transform(strPrefixOnFile.begin(), strPrefixOnFile.end(), strPrefixOnFile.begin(), ::toupper);
std::transform(strFilePrefix.begin(), strFilePrefix.end(), strFilePrefix.begin(), ::toupper);
if (totalSize > 0 && strcmp(strFilePrefix.c_str(), strPrefixOnFile.c_str()) == 0)
{
dirListData->strMatchedFilenames.emplace_back(izard, totalSize);
}
return totalSize;
}
BOOL GetDirectoryListFromSFTP(SftpConnectionInfo connectionInfo, GetDirListData *dirListData)
{
CURL* curl;
CURLcode result = CURLE_GOT_NOTHING;
char errbuff[CURL_ERROR_SIZE];
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, connectionInfo.strServerPath.c_str());
curl_easy_setopt(curl, CURLOPT_USERNAME, connectionInfo.strUsername.c_str());
curl_easy_setopt(curl, CURLOPT_PASSWORD, connectionInfo.strPassword.c_str());
curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_SFTP);
curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, GetDirListCallbackFunction);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, dirListData);
curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, "+diffie-hellman-group1-sha1");
curl_easy_setopt(curl, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PASSWORD);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuff); // Will provide a detailed error message if a CURL error occurs.
errbuff[0] = 0; // Must make sure this buffer is empty prior to use.
result = curl_easy_perform(curl);
}
curl_easy_cleanup(curl);
curl_global_cleanup();
return result == CURLE_OK;
}
That code just looks in the SFTP to find files with the various prefixes, like order and ack. I have put breakpoints in the callback function, but it does not seem to get there. The error appears on the curl_easy_perform line.
I have also tried to do CURLOPT_VERBOSE, but for some reason no matter what I try with that the output file for that remains empty.
We are going to be working on a modernized replacement for this eventually, but another app is ahead of it in that queue so this change needs to be done in the meantime.
Anyone have any ideas to help?
Thank you! <3