I am very new to libcurl. So any help is appreciated.
I am trying to download multiple files from CDN. The total size is around 600mb.
This is the piece of code where I am setting CURL handles(Inside a method named "addTransfers()"). (cm is of type CURLM*)
CURL *ceh = curl_easy_init();
curl_easy_setopt(ceh, CURLOPT_URL, reqURL.c_str());
curl_easy_setopt(ceh, CURLOPT_USERPWD, usrpwd);
curl_easy_setopt(ceh, CURLOPT_WRITEDATA, file);
curl_easy_setopt(ceh, CURLOPT_PRIVATE, file);
curl_easy_setopt(ceh, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(ceh, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(ceh, CURLOPT_CONNECTTIMEOUT, 10L);
curl_easy_setopt(ceh, CURLOPT_TIMEOUT, 150L);
curl_multi_add_handle(cm, ceh);
This is the code where I am performing the curl multi process:
bool do_multiple_downloads()
{
CURLM *cm;
CURLMsg *msg;
unsigned int transfers = 0;
int pending = 1;
int msg_pending = -1;
curl_global_init(CURL_GLOBAL_ALL);
cm = curl_multi_init();
curl_multi_setopt(cm, CURLMOPT_MAXCONNECTS, maxConnects);
for(transfers = 0; transfers < (int)maxConnects; transfers++)
{
if(!addTransfers(cm, transfers))
{
//Error
return false;
}
}
int i = 0;
do
{
/* code */
CURLMcode cPerformCode = curl_multi_perform(cm, &pending);
if(cPerformCode != CURLM_OK)
{
fprintf(stderr, "Error --> (%s) : Pending --> (%d)", curl_multi_strerror(cPerformCode), pending);
return false;
}
while((msg = curl_multi_info_read(cm, &msg_pending)))
{
if(msg != NULL)
{
if(msg->msg == CURLMSG_DONE)
{
FILE* writtenFile;
char* fname;
CURL *e = msg->easy_handle;
curl_easy_getinfo(e, CURLINFO_PRIVATE, &writtenFile);
fprintf(stderr, "R: %d - %s (%d)\n",
msg->data.result, curl_easy_strerror(msg->data.result), i++);
curl_multi_remove_handle(cm, e);
fclose(writtenFile);
curl_easy_cleanup(e);
}
else
{
fprintf(stderr, "E: CURLMsg (%d) : (%d)\n", msg->msg, i++);
}
if(transfers < totalSize)
{
if(!addTransfers(cm, transfers++))
{
//Error
fprintf(stderr, "Additional transfers addition\n");
return false;
}
}
}
}
if(pending)
{
curl_multi_wait(cm, NULL, 0, 1000, NULL);
}
} while (pending || (transfers < totalSize));
curl_multi_cleanup(cm);
curl_global_cleanup();
return true;
}
These are the scenarios:
Sometimes it works fine and all files are downloaded - No problem
Sometimes the downloads are completed, but the program is still inside the do-while loop(pending variable never becomes zero)
If I disconnect from the internet when the process is happening, the program stays inside the do-while loop. When I reconnect to the internet, Scenario 2 occurs.
Am I missing something here?? I might have done something silly here. Not sure though.
Thanks in advance.
Related
I'm trying to get a response code for HTTP request inside WriteCallback. I'm sure it worked in my main app just a few days ago, but doesn't work now. However, I tried to checkout previous branch and commits in git, actually they have the same problem now. I cann't give you full reproducible code because it's too large and complex, but I can show you my test app which illustrates what I'm doing:
#include "curl/curl.h"
#include <iostream>
#include <string>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "crypt32")
#pragma comment(lib, "normaliz.lib")
#pragma comment(lib, "legacy_stdio_definitions.lib")
namespace details {
FILE _iob[] = { *stdin, *stdout, *stderr };
}
extern "C" FILE* __cdecl __iob_func(void)
{
return details::_iob;
}
using namespace std;
CURL* curl = nullptr;
size_t writeData(void* ptr, size_t size, size_t nmemb, FILE* stream)
{
long responseCode = -1;
auto errorCode = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); // POINT 1
if (errorCode || (responseCode != 200 && responseCode != 206)) {
cout << "\n writeData FAILED: errorCode: " << errorCode << ", responseCode " << responseCode << '\n';
return 0;
}
size_t written = fwrite(ptr, size, nmemb, stream);
return written;
}
size_t headerWriter(void* contents, size_t size, size_t nmemb, void* userp)
{
auto header = (std::string((char*)contents, size * nmemb));
cout << "Got header: " << header;
return size * nmemb;
}
int сurlProgressCallback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
return CURL_PROGRESSFUNC_CONTINUE;
}
bool setupCurl(CURL* curl, const std::string& url, FILE* file)
{
static const std::string userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3202.75 "
"Safari/537.36 MyApp";
bool hasError = (bool)curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent.c_str());
hasError |= (bool)curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
hasError |= (bool)curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
hasError |= (bool)curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
hasError |= (bool)curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
hasError |= (bool)curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5);
hasError |= (bool)curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
hasError |= (bool)curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
hasError |= (bool)curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
hasError |= (bool)curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headerWriter);
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, сurlProgressCallback);
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, curl);
return hasError;
}
FILE* openFile(const std::string& filePath)
{
auto deleteSuccess = DeleteFileA(filePath.c_str());
if (!deleteSuccess) {
auto error = GetLastError();
if (error != ERROR_FILE_NOT_FOUND) {
cout << "Failed to delete file " << filePath << ", code " << std::to_string(error) << '\n';
return nullptr;
}
}
FILE* file = nullptr;
auto error = fopen_s(&file, filePath.c_str(), "wb");
if (error) {
cout << "Cann't open file " << filePath << '\n';
}
return file;
}
int main()
{
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (!curl) {
return -1;
}
const std::string filePath = "C:\\test-curl.txt";
FILE* file = openFile(filePath);
if (!file) {
return -1;
}
const std::string url = "https://curl.se/docs/manpage.html";
bool hasError = setupCurl(curl, url, file);
if (hasError) {
return -1;
}
auto errorCode = curl_easy_perform(curl);
if (errorCode) {
cout << "Curl failed: error code " << errorCode << '\n';
} else {
cout << "\nFinished successfully\n";
}
long responseCode = -1;
errorCode = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); // POINT 2
if (errorCode) {
cout << "\n failed to get response code\n";
}
fclose(file);
curl_easy_cleanup(curl);
curl_global_cleanup();
return 0;
}
I omitted some checks and proper deinitializing for brevity. This test app works as expected and it uses the same static build of libcurl as my main app. The problem is my main app gets an CURLE_UNKNOWN_OPTION error at point 1:
auto errorCode = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); // errorCode == CURLE_UNKNOWN_OPTION
The curl_easy_getinfo returns CURLE_OK at point 2 in both apps. I'm sure I didn't change any system settings and I didn't make a libcurl recompilation.
Questions are: should curl_easy_getinfo for CURLINFO_RESPONSE_CODE actually work inside write callback? If yes, what may cause it to fail and return an CURLE_UNKNOWN_OPTION error?
P.S.: I found that in my main app I'm getting CURLE_UNKNOWN_OPTION also in progress callback and write header callback.
P.P.S.: I also found that I'm getting CURLE_UNKNOWN_OPTION error for any info parameter - e.g., I tried CURLINFO_EFFECTIVE_METHOD, CURLINFO_EFFECTIVE_URL and CURLINFO_HTTP_VERSION.
Holy Grail, sorry. I'm feeling so stupid. In my main app I just forgot to update a curl handle after clearing a buffer which I pass to callback as user' structure. So CURLE_UNKNOWN_OPTION in my case actually just meant somethin like "Invalid curl handle".
I am currently using the multi interface API of the libcurl library to send multiple HTTP requests without blocking. My current problem is that I can't send a HTTP request.
For some reason maxfd is always -1 which result in rc always being 0. So when the code get to the switch statement it always print "timeout" because rc is always 0.
I never used the mulit interface before but I used the easy interface a couple of time. Much of the code is very similar to this.
ReqestHandler.cpp
void RequestHandler::add(lua_State* lua, const std::string& url, const std::string& data) {
Request request;
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "RoBot/ Version 1");
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &request.response);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &request.headers);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &request.code);
if (!data.empty()) {
curl_easy_setopt(curl, CURLOPT_POST, true);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
}
request.curl = curl;
request.lua = lua;
curl_multi_add_handle(_curlm, curl);
_requests.push_back(request);
}
void RequestHandler::tick() {
if (!_requests.empty()) {
curl_multi_perform(_curlm, &_isRunning);
do {
struct timeval timeout;
int rc;
CURLMcode mc;
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd = -1;
long curl_timeo = -1;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
curl_multi_timeout(_curlm, &curl_timeo);
if (curl_timeo >= 0) {
timeout.tv_sec = curl_timeo / 1000;
if (timeout.tv_sec > 1) {
timeout.tv_sec = 1;
} else {
timeout.tv_usec = (curl_timeo % 1000) * 1000;
}
}
mc = curl_multi_fdset(_curlm, &fdread, &fdwrite, &fdexcep, &maxfd);
if (mc != CURLM_OK) {
throw new Exception("MC error code: " + mc);
break;
}
if (maxfd == -1) {
Sleep(1000);
rc = 0;
} else {
rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
}
switch (rc) {
case -1:
/* select error */
std::cout << "Error" << std::endl;
break;
case 0:
/* timeout */
std::cout << "Timeout" << std::endl;
break;
default:
/* action */
std::cout << "Action" << std::endl;
curl_multi_perform(_curlm, &_isRunning);
break;
}
} while (_isRunning);
while ((_msg = curl_multi_info_read(_curlm, &_msgsLeft))) {
std::cout << "RAN";
if (_msg->msg == CURLMSG_DONE) {
for (unsigned int i = 0; i < _requests.size(); i++) {
Request request = _requests[i];
if (_msg->easy_handle == request.curl) {
std::cout << request.response << std::endl;
break;
}
}
}
}
curl_multi_cleanup(_curlm);
for (unsigned int i = 0; i < _requests.size(); i++) {
curl_easy_cleanup(_requests[i].curl);
_requests.erase(_requests.begin() + i);
}
}
}
RequestHandler.h
#pragma once
#include <string>
#include <vector>
#include "curl\curl.h"
#include "Lua\lua.hpp"
struct Request {
std::string response;
std::string headers;
int code;
CURL* curl;
lua_State* lua;
};
class RequestHandler {
public:
RequestHandler();
~RequestHandler();
static RequestHandler* getInstance();
void add(lua_State* lua, const std::string& url, const std::string& data);
void tick();
private:
static RequestHandler* INSTANCE;
std::vector<Request> _requests;
CURLM* _curlm;
CURLMsg* _msg;
int _isRunning;
int _msgsLeft;
};
Update
As suggested in the comment I used CURLOPT_STDERR and CURLOPT_VERBOSE and nothing printed to the output file.
I added this code within the RequestHandler:add(); function.
#ifdef _DEBUG
FILE* file = fopen("../Logs/Verbose.log", "wb");
curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
curl_easy_setopt(curl, CURLOPT_STDERR, file);
#endif
The file does get created but nothing get written to the file.
In the project I am working on , I am required to make a GET call and POST call when ever necessary. The "GET" call is used to create a downchannel from the server to the device to monitor for any interesting events that are happen in the cloud server. The "POST" call is used to send the data to the server. The server has a restriction that only a single connection has to be maintained with the server. Since the server supports HTTP2 , I am using "CURLMOPT_MAX_HOST_CONNECTIONS" and by setting it to 1 , I am making CURL to use 1 connection and I am using CURLMOPT_PIPELINING and by setting it to CURLPIPE_MULTIPLEX , I am multiplexing the transfers. The issue is that the code crashes when "curl_multi_perform" is called on the second thread.
PS: This is a part of my original code and might not compile/run straight away.
#include <stdio.h>
#include <string>
#include <sstream>
#include <curl.h>
#include <pthread.h>
#define EVENTS_URL "https://avs-alexa-na.amazon.com/v20160207/events"
#define DOWNCHANNEL_URL "https://avs-alexa-na.amazon.com/v20160207/directives"
CURLM *multi_handle;
CURL *downchannel_handle;
CURL *eventHttp_handle;
size_t processDownchannelResponse(void *ptr, size_t size, size_t nmemb, void *instance)
{
printf(" There is downchannel response.");
}
size_t eventResponse(void *ptr, size_t size, size_t nmemb, void *instance)
{
printf("We got eventResponse");
}
/* The downchannel thread needs to be running always
, if the transfer is done the connection is closed
we need to open a new connection and wait for more events*/
void createDownchannel()
{
int retryCount =0;
std::string downchURL = DOWNCHANNEL_URL;
long response_code;
int runninghandles =0;
downchannel_handle = curl_easy_init();
if(downchannel_handle == NULL){
printf("createDownchannel : Not able to create curl handle");
return ;
}
struct curl_slist *header = NULL;
header = curl_slist_append(header, "Host: avs-alexa-na.amazon.com");
header = curl_slist_append(header, "TOKEN GOES HERE");
curl_easy_setopt(downchannel_handle, CURLOPT_URL, downchURL.c_str());
curl_easy_setopt(downchannel_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(downchannel_handle, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(downchannel_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
curl_easy_setopt(downchannel_handle, CURLOPT_WRITEFUNCTION, processDownchannelResponse);
curl_easy_setopt(downchannel_handle, CURLOPT_WRITEDATA, NULL);
curl_easy_setopt(downchannel_handle, CURLOPT_PIPEWAIT, 1L);
if (header)
curl_easy_setopt(downchannel_handle, CURLOPT_HTTPHEADER, header);
if(multi_handle)
/* add the individual easy handle */
curl_multi_add_handle(multi_handle, downchannel_handle);
mbexitdownchannelthread = 1;
do{
CURLMcode mc;
int numfds;
mc = curl_multi_perform(multi_handle, &runninghandles);
if(mc != CURLM_OK) {
fprintf(stderr, "curl_multi failed, code %d.n", mc);
printf(“a<---curl_multi failed, code %d.n", mc);
break;
}
printf("a<--downchannel while");
// downchannel timeout can be higher 10 seconds
mc = curl_multi_wait(multi_handle, NULL, 0, 10000, &numfds);
if(mc != CURLM_OK) {
fprintf(stderr, "curl_multi failed, code %d.n", mc);
printf("a<---curl_multi failed, code %d.n", mc);
break;
}
}while(!mbexitdownchannelthread);
curl_multi_remove_handle(multi_handle, downchannel_handle);
curl_easy_cleanup(downchannel_handle);
if (header)
curl_slist_free_all(header);
}
bool getTransferStatus(CURLM *multiHandleInstance,CURL *currentHandle,std::string& contentType,int* http_status_code)
{
//check the status of transfer CURLcode return_code=0;
int msgs_left=0;
CURLMsg *msg=NULL;
CURL *eh=NULL;
CURLcode return_code;
bool msgTrasferDone = false;
while ((msg = curl_multi_info_read(multiHandleInstance, &msgs_left)))
{
if (msg->msg == CURLMSG_DONE) {
eh = msg->easy_handle;
if(currentHandle == eh)
{
msgTrasferDone = true;
return_code = msg->data.result;
if(return_code!=CURLE_OK)
{
//fprintf(stderr, "CURL error code: %d\n", msg->data.result);
printf("a<--return_code!=CURLE_OK CURL error code: %d\n", msg->data.result);
continue;
}
// Get HTTP status code
*http_status_code=0;
char* ch= NULL;
curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, http_status_code);
printf("a<--CURLINFO_RESPONSE_CODE=%d",*http_status_code);
curl_easy_getinfo(eh, CURLINFO_CONTENT_TYPE, &ch);
contentType.clear();
if(ch!=NULL)
contentType.append(ch);
}
}
}
return msgTrasferDone;
}
int eventThread()
{
int still_running = 0;
std::string contentType;
int responseCode = 0;
int numfds = 0;
std::string postUrl;
postUrl.assign(EVENTS_URL);
// init the curl session
CURL *eventHttp_handle;
CURLcode res;
eventHttp_handle = curl_easy_init();
//assign speech buffer pointer for read callbacks
curl_easy_setopt(eventHttp_handle, CURLOPT_URL, postUrl.c_str());
curl_easy_setopt(eventHttp_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(eventHttp_handle, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(eventHttp_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
/* wait for pipe connection to confirm */
curl_easy_setopt(eventHttp_handle, CURLOPT_PIPEWAIT, 1L);
curl_easy_setopt(eventHttp_handle, CURLOPT_WRITEFUNCTION, eventResponse);
curl_easy_setopt(eventHttp_handle, CURLOPT_WRITEDATA, NULL);
struct curl_slist *header = NULL;
header = curl_slist_append(header, "Host: avs-alexa-na.amazon.com");
header = curl_slist_append(header, "TOKEN GOES HERE");
if (header)
curl_easy_setopt(eventHttp_handle, CURLOPT_HTTPHEADER, header);
if (multi_handle)
curl_multi_add_handle(multi_handle, eventHttp_handle);
do
{
{
CURLMcode mc;
int numfds;
mc = curl_multi_perform(multi_handle, &still_running);
if(mc != CURLM_OK) {
fprintf(stderr, "curl_multi failed, code %d.n", mc);
printf("a<---curl_multi failed, code %d.n", mc);
break;
}
mc = curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds);
if(mc != CURLM_OK) {
fprintf(stderr, "curl_multi failed, code %d.n", mc);
printf("a<---curl_multi failed, code %d.n", mc);
break;
}
}
}while(!getTransferStatus(multi_handle,eventHttp_handle,contentType,&responseCode));
if (header)
curl_slist_free_all(header);
if (formpost)
{
curl_formfree(formpost);
formpost = NULL;
}
printf("a<-- CURL HTTP RESP CODE =%d",responseCode);
curl_multi_remove_handle(multi_handle, eventHttp_handle);
curl_easy_cleanup(eventHttp_handle);
return 0;
}
int main ()
{
multi_handle = curl_multi_init();
curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 1L);
// create a downchannel thread
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int err = pthread_create(&mPostThread, &attr, downchannelThread,NULL);
pthread_attr_destroy(&attr);
// i am doing some work here //
sleep(3);
// create a event thread
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int err = pthread_create(&mPostThread, &attr, eventThread,NULL);
pthread_attr_destroy(&attr);
}
I am working on a C++ program, which uses cURL lib. When I try to connect to URL, that is incorrect or the page is down I get following error :
getaddrinfo(3) failed for www.wp.pl#:80
Couldn't resolve host 'www.wp.pl#'
And the program terminates. And that is the problem, because I it to go futher and connect to other pages. I just won't parse and analyze the broken page I don't want to end my program after come across such one.
I posted similar topic, but it contained only snippets of code so it was diffcult for you to say what is wrong, now I will post whole code.
int PageHandler::getCleanAndRepairedPage(string pageURL, string& outDoc)
throw (exception) {
if (find(visitedPages.begin(), visitedPages.end(), pageURL)
!= visitedPages.end()) {
// url has already been visited
outDoc = "";
return VISITED_PAGE_ERROR;
} else { // new url
visitedPages.push_back(pageURL);
char *charURL;
charURL = const_cast<char*> (pageURL.c_str());
CURL *curl;
char curl_errbuf[CURL_ERROR_SIZE];
TidyBuffer output = { 0 };
TidyBuffer errbuf = { 0 };
TidyBuffer docbuf = { 0 };
TidyDoc tdoc = tidyCreate(); // Initialize "document"
tidyOptSetBool(tdoc, TidyForceOutput, yes);
tidyOptSetInt(tdoc, TidyWrapLen, 4096);
tidyBufInit(&docbuf);
int rc = -1;
Bool ok;
curl = curl_easy_init();
curl_easy_setopt( curl, CURLOPT_URL, charURL );
curl_easy_setopt( curl, CURLOPT_ERRORBUFFER, curl_errbuf );
curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, write_cb );
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt( curl , CURLOPT_WRITEDATA, &docbuf );
int err;
err = curl_easy_perform(curl);
cout << "curl_easy_perfom return value = " << err << endl;
if (!err) {
ok = tidyOptSetBool(tdoc, TidyXhtmlOut, yes); // Convert to XHTML
if (ok) {
rc = tidySetErrorBuffer(tdoc, &errbuf); // Capture diagnostics
if (rc >= 0) {
rc = tidyParseBuffer(tdoc, &docbuf); // parse the buffer
}
if (rc >= 0) {
rc = tidyCleanAndRepair(tdoc); // Tidy it up!
}
if (rc >= 0) {
rc = tidyRunDiagnostics(tdoc); // Kvetch
}
if (rc > 1) { // If error, force output.
rc = (tidyOptSetBool(tdoc, TidyForceOutput, yes) ? rc : -1);
}
if (rc >= 0) {
rc = tidySaveBuffer(tdoc, &output); // Pretty Print
}
}
if (rc >= 0) {
if (rc > 0) {
//printf("\nDiagnostics:\n\n%s", errbuf.bp);
}
} else {
printf("A severe error (%d) occurred.\n", rc);
}
} else {
printf("%s\n", curl_errbuf);
}
if (err == NO_ERROR) {
string tmp(reinterpret_cast<char const*> (output.bp));
outDoc = tmp;
} else {
outDoc = "";
}
curl_easy_cleanup(curl);
tidyBufFree(&docbuf);
tidyBufFree(&output);
tidyBufFree(&errbuf);
tidyRelease(tdoc);
return err; // err == 0 <=> everything ok!
}
}
And the console output :
EDIT : I forgot to say what is going on on console output. I connect to many pages and the invalid URL is just one of them. At the beginning you can see a succesful connection and cURL messages about it, the result of curl_easy_perform equals 0, which indicate that everything went good. Next message is about connection to the invalid URL, as u can see return value of curl_easy_perform is 6, which is not good.
"www.wp.pl#" is not a legal URL and it causes libcurl to (mistakenly) use the entire string as a host name, and you don't have any such and the operation fails.
I am using libssh to send a remote command to a computer. This command is real time so I am trying to get databack as it is generated. Basically I am hexdumping a mouse event and I want that data as it comes in. How can I make this return realtime results from my command?
#include <libssh/libssh.h>
#include <stdio.h>
#include <stdlib.h>
/*
* 1) Set ssh options
* 2) Connect
* 3) Authenticate
* 4) Set channels
* 5) Execute command
* */
int main()
{
//Initilization
ssh_session session;
int verbosity = SSH_LOG_PROTOCOL;
int port = 22;
char* password ="root";
int rc;
session = ssh_new();
if (session == NULL)
return(-1);
//Set options for SSH connection
ssh_options_set(session,SSH_OPTIONS_HOST,"90.12.34.44");
ssh_options_set(session,SSH_OPTIONS_LOG_VERBOSITY,&verbosity);
ssh_options_set(session,SSH_OPTIONS_PORT,&port);
ssh_options_set(session,SSH_OPTIONS_USER,"root");
//Connect to server
rc = ssh_connect(session);
if (rc != SSH_OK)
{
fprintf(stderr,"Error connecting to host %s\n",ssh_get_error(session));
ssh_free(session);
return(-1);
}
rc = ssh_userauth_password(session,NULL,password);
if ( rc == SSH_AUTH_SUCCESS)
{
printf("Authenticated correctly");
}
ssh_channel channel;
channel = ssh_channel_new(session);
if(channel == NULL) return SSH_ERROR;
rc = ssh_channel_open_session(channel);
if (rc != SSH_OK)
{
ssh_channel_free(channel);
return rc;
}
rc = ssh_channel_request_exec(channel,"hd /dev/input/event0");
if (rc != SSH_OK)
{
ssh_channel_close(channel);
ssh_channel_free(channel);
return rc;
}
char buffer[30];
unsigned int nbytes;
nbytes = ssh_channel_read(channel,buffer,sizeof(buffer),0);
while(nbytes > 0)
{
if(fwrite(buffer,1,nbytes,stdout));
{
ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
nbytes = ssh_channel_read(channel,buffer,sizeof(buffer),0);
if (nbytes < 0)
{
ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
return 0;
}
}
If you want to get asynchronous real-time responses from remote file being changed, you'd better try some special async I/O API, like libevent. You will have to write your own client and server, but it's quite simple.
Are you sure you need an encrypted connection? If you are, openSSL is supported by libevent too.
The Problem is in this line my friend
nbytes = ssh_channel_read(channel,buffer,sizeof(buffer),0);
The last parameters is (0) Zero . If you Change it to (1) one , function will fill the buffer with the result of your Command . :D That's it