I have a file pointer, such as the following:
FILE* f = tmpfile()
How do I use libcurl to do a HTTP POST to a URL as a field named F1?
I tried reading the file contents into a char* array but and used the following to upload:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
char* dump_buffer(void *buffer, int buffer_size){
int i;
char *ch = malloc(buffer_size);
for(i = 0;i < buffer_size;++i){
ch[i] = ((char *)buffer)[i];
//printf("%c",((char *)buffer)[i]);
}
return ch;
}
char* readFileBytes(const char *name){
FILE *file;
char *buffer;
unsigned long fileLen;
int i;
file = fopen("index.tar", "rb");
if (!file)
{
fprintf(stderr, "can't open file %s", "1.m4v");
exit(1);
}
fseek(file, 0, SEEK_END);
fileLen=ftell(file);
fseek(file, 0, SEEK_SET);
buffer=(char *)malloc(fileLen+1);
if (!buffer)
{
fprintf(stderr, "Memory error!");
fclose(file);
exit(1);
}
fread(buffer, fileLen, 1, file);
fclose(file);
char* ret = dump_buffer(&buffer, fileLen);
for(i = 0;i < fileLen;++i){
//printf("%c",ret[i]);
}
return ret;
}
int main(int argc, char *argv[])
{
CURL *curl;
CURLcode res;
struct curl_httppost *formpost=NULL;
struct curl_httppost *lastptr=NULL;
struct curl_slist *headers=NULL;
headers = curl_slist_append(headers, "Content-Type: multipart/form-data");
curl_global_init(CURL_GLOBAL_ALL);
/* Fill in the filename field */
char* p = readFileBytes("index.tar");
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "F2",
CURLFORM_FILE, "index.tar",
CURLFORM_END);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "F1",
CURLFORM_COPYCONTENTS, (char*)p,
CURLFORM_END);
curl = curl_easy_init();
/* initalize custom header list (stating that Expect: 100-continue is not
wanted */
if(curl) {
/* what URL that receives this POST */
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_URL, "http://oceanfizz.usc.edu/upload.php");
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
/* then cleanup the formpost chain */
curl_formfree(formpost);
/* free slist */
}
return 0;
}
The output that I get is
guest-wireless-207-151-246-070:Desktop ankurcha$ ./postit2
* About to connect() to oceanfizz.usc.edu port 80 (#0)
* Trying 128.125.49.29... * connected
* Connected to oceanfizz.usc.edu (128.125.49.29) port 80 (#0)
> POST /upload.php HTTP/1.1
Host: oceanfizz.usc.edu
Accept: */*
Content-Length: 20770
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------e04b6194f620
< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Date: Mon, 19 Apr 2010 03:51:04 GMT
< Server: Apache/2.2.12 (Ubuntu)
< X-Powered-By: PHP/5.2.10-2ubuntu6.4
< Vary: Accept-Encoding
< Content-Length: 335
< Content-Type: text/html
<
array(1) {
["F2"]=>
array(5) {
["name"]=>
string(9) "index.tar"
["type"]=>
string(24) "application/octet-stream"
["tmp_name"]=>
string(14) "/tmp/phpyOiqXh"
["error"]=>
int(0)
["size"]=>
int(20480)
}
}
array(1) {
["F1"]=>
string(0) ""
}
Sorry, there was a problem uploading your file.
* Connection #0 to host oceanfizz.usc.edu left intact
* Closing connection #0
I was expecting F1 to have binary content.
A HTTP POST can be done in many ways so there's not a single answer unless you specify more details in the question. One way to do POST programmatically with libcurl is as shown in this example:
http://curl.haxx.se/libcurl/c/post-callback.html
If you rather want to do a multipart formpost upload, possibly a better example is this:
http://curl.haxx.se/libcurl/c/postit2.html
You upload code works fine. The file uploaded is stored in a temporary file /tmp/phpyOiqXh. PHP won't store the content of uploaded file to a variable, just store the temp file's path.
Related
i am trying to implement a quite specialized email-client using libcurl (7.66) for sending the email.
Sadly, it always crashes on calling curl_easy_perform(curl), no matter what i try whatsoever.
Currently in the process_mail callback i have commented everything out; just returning 0. I am pretty shure, this should be enough for at least not crasing the app ...
The real goal would be having the mail as a string in the memory and just copy it over to the stream.
I really appreciate any kind of help ... i have quite a delay because of this issue.
Here is the header-file:
#ifndef MAILMESSAGE_H
#define MAILMESSAGE_H
#include <QObject>
#include <QDebug>
#include <QFile>
#include <QIODevice>
#include <QByteArray>
#include <curl/curl.h>
#include <stdio.h>
class MailMessage : public QObject
{
Q_OBJECT
public:
explicit MailMessage(QObject *parent = nullptr);
void setSMTPPort(QString smtp_port);
void setSMTPAddress(QString smtp_address);
void setSMTPUser(QString smtp_user);
void setSMTPPassword(QString smtp_password);
void addTo(QString address_to);
void setFrom(QString address_from);
void setSubject(QString subject);
void setAlternativeText(QString text);
void setHTML(QString html);
void addAttachment(QString attachment_path, QString filename);
void generateMessage();
// return POSIX-style: 0: ok; 1: error
int sendMail();
QString message;
int message_size;
const char* message_char;
QString smtp_port;
QString smtp_address;
QString smtp_user;
QString smtp_password;
//QStringList addresses_to;
QString address_to;
QString address_from;
QString subject;
QString payload_text;
QString payload_html;
QStringList attachments_base64;
double upload_speed;
double upload_time;
protected:
static size_t process_mail(void *ptr, size_t size, size_t nmemb, void *userp);
signals:
public slots:
};
#endif // MAILMESSAGE_H
And the relevant parts of the implementation:
void MailMessage::generateMessage()
{
this->message = //"To: "+ this->address_to +"\r\n"
"From: "+ this->address_from +"\r\n"
"Subject: "+ this->subject +"\r\n"
"Content-Type: multipart/mixed; boundary=MixedBoundary"
"\r\n"
"--MixedBoundary"
"Content-Type: multipart/alternative; boundary=AlternativeBoundary"
"\r\n"
"--AlternativeBoundary"
"Content-Type: text/plain; charset=\"utf-8\""
"\r\n"+ this->payload_text +"\r\n"
"--AlternativeBoundary"
"Content-Type: text/html; charset=\"utf-8\""
"\r\n"+ this->payload_html +"\r\n"
"--AlternativeBoundary--"
"\r\n"
"--MixedBoundary";
/*
"Content-Type: application/pdf; name=\"HelloWorld.pdf\""
"Content-Transfer-Encoding: base64"
"Content-Disposition: attachment; filename=\"HelloWorld.pdf\"";
*/
this->message.append("\r\n"
"--MixedBoundary--");
QByteArray array = this->message.toLocal8Bit();
this->message_char = array.data();
this->message_size = sizeof(this->message_char);
}
size_t MailMessage::process_mail(void *ptr, size_t size, size_t nmemb, void *userprocess)
{
size_t retcode = 0;
/*
MailMessage *self = reinterpret_cast<MailMessage*>(userprocess);
if (sizeof(self->message_char) == 0)
return retcode;
retcode = (size * nmemb >= sizeof(self->message_char)) ? sizeof(self->message_char) : size * nmemb;
self->message_size -= retcode;
memcpy(ptr, self->message_char, retcode);
self->message_char += retcode;
*/
return retcode;
}
int MailMessage::sendMail()
{
//qDebug() << this->message;
CURLcode res = CURLE_OK;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
// CURLUSESSL_ALL, CURLUSESSL_NONE, CURLUSESSL_TRY, CURLUSESSL_CONTROL
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
curl_easy_setopt(curl, CURLOPT_URL, this->smtp_address.toStdString().c_str());
curl_easy_setopt(curl, CURLOPT_USERNAME, this->smtp_user.toStdString().c_str());
curl_easy_setopt(curl, CURLOPT_PASSWORD, this->smtp_password.toStdString().c_str());
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, this->address_from.toStdString().c_str());
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, this->address_to.toStdString().c_str());
curl_easy_setopt(curl, CURLOPT_READFUNCTION, &MailMessage::process_mail);
curl_easy_setopt(curl, CURLOPT_READDATA, this);
/* Send the message */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
else
{
curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &upload_speed);
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &upload_time);
qDebug() << "Speed: "+QString::number(upload_speed) + " Time: "+QString::number(upload_time);
}
//curl_slist_free_all(this->address_to.toStdString().c_str());
curl_easy_cleanup(curl);
return 0;
}
And finally some excerpt of the console output:
* start date: May 8 08:01:21 2019 GMT
* expire date: May 13 23:59:59 2021 GMT
* subjectAltName: host "mail.gmx.net" matched cert's "mail.gmx.net"
* issuer: C=DE; O=T-Systems International GmbH; OU=T-Systems Trust Center; ST=Nordrhein Westfalen; postalCode=57250; L=Netphen; street=Untere Industriestr. 20; CN=TeleSec ServerPass Extended Validation Class 3 CA
* SSL certificate verify ok.
> EHLO cf-19
* SMTP 0x5572580cd700 state change from UPGRADETLS to EHLO
< 250-gmx.com Hello cf-19 [2.202.204.204]
* Curl_pp_readresp_ 55 bytes of trailing server response left
< 250-8BITMIME* Curl_pp_readresp_ 41 bytes of trailing server response left
< 250-AUTH LOGIN PLAIN
* Curl_pp_readresp_ 19 bytes of trailing server response left
< 250 SIZE 69920427
> AUTH PLAIN
* SASL 0x5572580cd780 state change from STOP to PLAIN
* SMTP 0x5572580cd700 state change from EHLO to AUTH
< 334
> AHNhbXVlbF9iZWNrZXJAZ214LmRlADI4OTZhY2Q2
* SASL 0x5572580cd780 state change from PLAIN to FINAL
< 235 Authentication succeeded
* SASL 0x5572580cd780 state change from FINAL to STOP
* SMTP 0x5572580cd700 state change from AUTH to STOP
* STATE: PROTOCONNECT => DO handle 0x5572580d0678; line 1701 (connection #0)
* DO phase starts
> MAIL FROM:<xxxxxxx#xxx.xx>
* SMTP 0x5572580cd700 state change from STOP to MAIL
* STATE: DO => DOING handle 0x5572580d0678; line 1743 (connection #0)
< 250 Requested mail action okay, completed
03:37:55: The program has unexpectedly finished.
03:37:55: The process was ended forcefully.
QByteArray array = this->message.toLocal8Bit();
This creates a local QByteArray object, a local variable in the generateMessage() method. When generateMessage() returns, this object and everything in it will, of course, be destroyed just like any other function local variable. That's how local function variables work in C++.
this->message_char = array.data();
this->message_size = sizeof(this->message_char);
This saves a pointer to array's internal buffer in message_char. This also saves sizeof(this->message_char) in message_size. Since message_char is a const char *, this will always save sizeof(const char *), which will typically be 4 or 8 (depending on your operating system), in message_size, no matter how big the array is. That's already an obvious fail at this point, but not the ultimate fail that crashes the shown code.
The ultimate fail is that, as I've explained earlier, as soon as this function returns -- which is right about now (since this is the last statement in this function) -- array and all of its contents gets immediately destroyed. The aforementioned pointer to array's internal buffer will become a dangling pointer, to the internal contents of an object that no longer exists, and any further attempts to dereference this pointer results in undefined behavior, and a likely crash.
This is the obvious reason for your crash: improper usage of dangling pointers to destroyed objects. Additionally contributory factor is improper usage of sizeof (in the event your message's actual size happens to be less than the size of a pointer on your operating system).
I'm getting an inconsistent failure when trying to grab http data, using curl.
libcurl: (23) Failed writing body (23048858 != 16058)
It was continuously failing, then it started working. Now it's failing again. I've hunted around and most of the posts either blame the callback or the order of setting curl options. I've rearranged the options, and I don't see any problems with the callback. In fact when I debug the callback the input parameters match the output value that I am actually getting. So I'm not sure where this value of 23048858 comes from.
Source
SwReceiver* SwReceiver::instance;
SwReceiver *SwReceiver::getInstance(
std::string &address,
std::string &key,
std::string &options)
{
if(!instance)
{
instance = new SwReceiver(address, key, options);
return instance;
}
}
SwReceiver::SwReceiver(
std::string &address,
std::string &key,
std::string &options)
{
curl_global_init(CURL_GLOBAL_ALL);
data = curl_easy_init();
if(data)
{
std::string addrstr = address + '/' + key + '/' + options;
// std::cout << "Address = " << addrstr << std::endl;
curl_easy_setopt(data, CURLOPT_URL, addrstr.c_str());
curl_easy_setopt(data, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(data, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(data, CURLOPT_ERRORBUFFER, errorBuffer);
curl_easy_setopt(data, CURLOPT_WRITEFUNCTION, writeMemoryCallback);
memset(errorBuffer, 0, sizeof(CURL_ERROR_SIZE));
/* DEBUG */
curl_easy_setopt(data, CURLOPT_VERBOSE, 1);
runQuery();
}
else
{
//TODO add to error buffer
}
}
SwReceiver::~SwReceiver()
{
delete(instance);
curl_easy_cleanup(data);
}
void SwReceiver::runQuery()
{
result = curl_easy_perform(data);
if(result != CURLE_OK)
{
size_t len = strlen(errorBuffer);
fprintf(stderr, "\nlibcurl: (%d) ", result);
if(len)
{
fprintf(stderr, "%s%s", errorBuffer,
((errorBuffer[len - 1] != '\n') ? "\n" : ""));
}
else
{
fprintf(stderr, "%s\n", curl_easy_strerror(result));
}
}
}
MemoryStruct *SwReceiver::getData()
{
return &chunk;
}
size_t SwReceiver::writeMemoryCallback(
void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realSize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
char *ptr = (char*)realloc(mem->memory, mem->size + realSize + 1);
if(ptr == NULL)
{
//TODO This should write to the error buffer
std::cout << "Not enought memory!\n";
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realSize);
mem->size += realSize;
mem->memory[mem->size] = 0;
}
the memory struct source
struct MemoryStruct
{
char * memory;
size_t size;
MemoryStruct()
: memory((char*)malloc(1)),
size(0)
{
}
};
I didn't post the header for size reasons. If you feel I should post let me know.
DEBUG
(gdb)
(gdb) break 79
Breakpoint 1 at 0x40240c: file swreceiver.cpp, line 79.
(gdb) run
Starting program: /home/ubuntu/src/stickweather/stickweather
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff1de9700 (LWP 26989)]
[Thread 0x7ffff1de9700 (LWP 26989) exited]
* Trying 34.193.12.42...
* Connected to api.darksky.net (34.193.12.42) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:#STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: CN=darksky.net
* start date: Apr 26 00:00:00 2019 GMT
* expire date: May 26 12:00:00 2020 GMT
* subjectAltName: api.darksky.net matched
* issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
* SSL certificate verify ok.
> GET /forecast/<hidden>/37.8267,-122.4233 HTTP/1.1
Host: api.darksky.net
User-Agent: libcurl-agent/1.0
Accept: */*
< HTTP/1.1 200 OK
< Date: Tue, 22 Oct 2019 14:18:40 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 28035
< Connection: keep-alive
< X-Authentication-Time: 687ms
< X-Forecast-API-Calls: 13
< Cache-Control: max-age=60
< Expires: Tue, 22 Oct 2019 14:19:39 +0000
< X-Response-Time: 333.671ms
< Vary: Accept-Encoding
<
Thread 1 "stickweather" hit Breakpoint 1, SwReceiver::writeMemoryCallback (contents=0x650be6, size=1, nmemb=16058,
userp=0x635848) at swreceiver.cpp:82
82 size_t realSize = size * nmemb;
Your writeMemoryCallback does not return the number of bytes written, at the bottom control reaches the end of the function without a return, so on x86 it will probably return garbage. I'd suspect that is where the other value is coming from.
https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
I'm very new to HTTP commands and the libcurl library. I know how to get the HTTP response code but not the HTTP response string. Following is the code snippet that I wrote to get the response code. Any help on how to get the response string will be highly appreciated!!!
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
CURLcode ret = curl_easy_perform(curl);
if (ret != CURLE_OK) {
LOG(INFO) << "Failed to perform the request. "
<< "Return code: " << ret;
return false;
}
std::unique_ptr<int64_t> httpCode(new int64_t);
// Get the last response code.
ret = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, httpCode.get());
if (ret != CURLE_OK) {
LOG(INFO) << "curl_easy_getinfo failed to retrieve http code. "
<< "Return code: " << ret;
return false;
}
I tried doing this as well to get the HTTP response string in readBuffer.
static size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp)
{
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
CURLcode ret = curl_easy_perform(curl);
cout << readBuffer << "\n";
But the readBuffer is empty. I don't understand where I am going wrong. Any pointers on how to solve this will be really nice!
There doesn't look to be much wrong with your code. I ran the following code, based on yours, to read the front page of the BBC news website:
#include <iostream>
#include <string>
#include <curl/curl.h>
size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp)
{
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
int main(int argc, char * argv[])
{
curl_global_init(CURL_GLOBAL_ALL);
CURL* easyhandle = curl_easy_init();
std::string readBuffer;
curl_easy_setopt(easyhandle, CURLOPT_URL, "http://www.bbc.co.uk/news");
curl_easy_setopt(easyhandle, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(easyhandle, CURLOPT_PROXY, "http://my.proxy.net"); // replace with your actual proxy
curl_easy_setopt(easyhandle, CURLOPT_PROXYPORT, 8080L);
curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_perform(easyhandle);
std::cout << readBuffer << std::endl;
return 0;
}
... and I got the full HTML response. NB I had to use a proxy, and I enabled verbose mode to see what was happening. Also NB; the HTTP server might be fussy about the URL you give it: if I replace http://www.bbc.co.uk/news with http://www.bbc.co.uk/news/ (i.e. with a trailing slash) then I get no data back (a response length of zero), as noted by the verbose curl output:
Host: www.bbc.co.uk
Accept: */*
Proxy-Connection: Keep-Alive
< HTTP/1.1 301 Moved Permanently
< X-Cache-Action: PASS (no-cache-control)
< Vary: Accept-Encoding
< X-Cache-Age: 0
< Content-Type: text/html;charset=utf-8
< Date: Mon, 10 Jul 2017 16:42:20 GMT
< Location: http://www.bbc.co.uk/news
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< Content-Length: 0
< X-Cache: MISS from barracuda1.[my proxy].net
< Connection: keep-alive
<
* Connection #0 to host [my proxy] left intact
Here, Content-Length is 0 and the WriteCallback() function is never called. Hope this helps.
For the numerical response code, getinfo with CURLINFO_RESPONSE_CODE is the way to go:
long response_code;
curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE,&response_code);
However there is no equivalent getinfo capture for the server's response text. If you need the server's text, inspect the raw HTTP headers. There are two ways to do this:
Enable writing headers to the payload with CURLOPT_HEADER, then extract the headers from the combined payload, splitting the body on \n\n
Set a header callback function with CURLOPT_HEADERFUNCTION and parse directly from that
I use libcurl to do RTSP request. I set curl options as seen below:
FILE *tmpListDownloadFile;
tmpListDownloadFile = fopen(tmp.c_str(), "w");
if(tmpListDownloadFile != NULL)
{
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
char *p = curl_easy_unescape(curl, UriP, 0, NULL);
string s = p;
curl_free(p);
string uri = url + "/?" + s;
printf("%s uri:%s\n",__FUNCTION__,uri.c_str());
curl_version_info_data *d = curl_version_info(CURLVERSION_NOW);
printf("curl version:%s\n",d->version);
curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri.c_str());
curl_easy_setopt(curl, CURLOPT_RTSP_CLIENT_CSEQ, stRtspInfo.CSeq);
curl_easy_setopt(curl, CURLOPT_RTSP_TRANSPORT, transport.c_str());
curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)tmpListDownloadFile);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15);
curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE);
CURLcode curlResult = curl_easy_perform(curl);
char* session_id;
if(curl_easy_getinfo(curl, CURLINFO_RTSP_SESSION_ID, &session_id) == CURLE_OK)
{
printf("%s session_id:%s\n",__FUNCTION__, session_id);
if(NULL != session_id)
{
ostringstream ss;
ss << session_id;
stRtspInfo.sessionID = ss.str();
bIsSessionEstablished = true;
}
}
else
{
printf("%s getting session id failed\n",__FUNCTION__);
}
curl_easy_cleanup(curl);
curl_global_cleanup();
fclose(tmpListDownloadFile);
if (curlResult == CURLE_OK && bIsSessionEstablished == true)
{
...
}
else
{
printf("Setup failed\n");
}
}
And log messages are as below.
RtspSetup url:rtsp://10.134.158.71
RtspSetup transport:RTP/AVP;unicast;client_port=45636-45637
RtspSetup uri:rtsp://10.134.158.71/?src=1&freq=11054&sr=30000&pol=v&msys=dvbs2&mtype=8psk&fec=34&ro=0.35&plts=off&pids=0
curl version:7.21.3
* About to connect() to 10.134.158.71 port 554 (#0)
* Trying 10.134.158.71... * connected
* Connected to 10.134.158.71 (10.134.158.71) port 554 (#0)
> SETUP rtsp://10.134.158.71/?src=1&freq=11054&sr=30000&pol=v&msys=dvbs2&mtype=8psk&fec=34&ro=0.35&plts=off&pids=0 RTSP/1.0
CSeq: 1
Transport: RTP/AVP;unicast;client_port=45636-45637
If-Modified-Since: Thu, 01 Jan 1970 00:00:00 GMT
* HTTP 1.1 or later with persistent connection, pipelining supported
< RTSP/1.0 200 OK
< CSeq: 1
< Date: Sat, Jan 01 2000 00:14:11 GMT
< Transport: RTP/AVP;unicast;destination=10.134.158.14;source=10.134.158.71;client_port=45636-45637;server_port=6970-6971
< Session: E3C33231;timeout=60
< com.ses.streamID: 3
<
* Connection #0 to host 10.134.158.71 left intact
RtspSetup session_id:E3C33231
Altough I set Timecondition as none, if-modified-since are added to the header. I want to remove if-modified-since header. How to do this?
That's a bug in libcurl (that happens for some RTSP requests). Just now fixed in this commit. To be included in the upcoming next release: 7.46.0.
In windows, this code works file, but now, I want to convert it into ubuntu:
// callback read function to upload file from local to ftp server
size_t read_callback (void* ptr, size_t size, size_t nmemb, FILE *stream){
//return fread(ptr,size,nmemb, (FILE*) stream);
return fread(ptr,size,nmemb,stream);
}
// get file name from a path
string FTPClientConnector::getFileName(string path){
int length = path.size();
for(int i = length - 1; i >= 0; i--){
if(path[i] == '/' || path[i] == '\\'){
return path.substr(i+1, length-i-1);
}
}
}
//function to upload a file to FTP server
int FTPClientConnector::uploadFile(string filePath, string serverPath ){
CURL *curl;
CURLcode res;
FILE *hd_src;
struct stat file_info;
curl_off_t fsize;
char* local_file = new char[filePath.size()+1];
std::copy(filePath.begin(), filePath.end(), local_file);
local_file[filePath.size()] = '\0';
// stat the local file
if(stat(local_file, &file_info)){
printf("couldn't open file\n");
delete local_file;
return -1;
}
// convert URL and username and password to connect to remote server
string urlPath = this->hostName + serverPath;
urlPath += getFileName(filePath);
char *url = new char[urlPath.size() + 1];
std::copy(urlPath.begin(), urlPath.end(), url);
url[urlPath.size()] = '\0';
string userAndPassString = this->userName + ":" + this->password;
char* usernameAndPassword = new char[userAndPassString.size() +1];
std::copy(userAndPassString.begin(), userAndPassString.end(), usernameAndPassword);
usernameAndPassword[userAndPassString.size()] = '\0';
// get the file to open
hd_src = fopen(local_file, "rb");
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl){
/* specify target */
curl_easy_setopt(curl,CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_PORT, this->port);
curl_easy_setopt(curl, CURLOPT_USERPWD, usernameAndPassword);
/* we want to use our own read function */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
/* enable uploading */
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* now specify which file to upload */
curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
/* Now run off and do what you've been told! */
res = curl_easy_perform(curl);
if(res != CURLE_OK){
printf("Upload file failed!\n");
delete local_file;
delete url;
delete usernameAndPassword;
return -1;
}
curl_easy_cleanup(curl);
}
fclose(hd_src);
delete local_file;
delete url;
delete usernameAndPassword;
return 0;
}
This is what I call in main.cpp:
FTPClientConnector connector(host,user,password,port);
connector.uploadFile("xml/kingfisher.xml", "/xml_test_upload");
The code above doesn't work in Ubuntu with errors:
220 ProFTPD 1.3.4a Server (Debian) [::ffff:10.244.31.244]
500 PUT not understood
500 AUTHORIZATION: not understood
500 HOST: not understood
550 */*: Forbidden command argument
500 TRANSFER-ENCODING: not understood
500 EXPECT: not understood
500 Invalid command: try being more creative
500 2A2 not understood
Edit: This is my Makefile:
uploader:
g++ -o uploader FTPClientConnector.cpp main.cpp -lcurl
The output seems to indicate that you speak HTTP to a FTP server. Make sure your URL properly uses a FTP:// prefix for FTP, as without a protocol prefix libcurl guesses which protocol you want and it defaults to HTTP...
It appears from your comments that you need to use IPv4. Add this to your list of setopt calls:
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);