Json string in libcurl - c

Can I send a Json string using libcurl. I am new to both. Any kind of help would be appreciated. Basically i want to send a Json string using libcurl simple send and receive in C
My code is below:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* Auxiliary function that waits on the socket. */
static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms)
{
struct timeval tv;
fd_set infd, outfd, errfd;
int res;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec= (timeout_ms % 1000) * 1000;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
FD_SET(sockfd, &errfd); /* always check for error */
if(for_recv)
{
FD_SET(sockfd, &infd);
}
else
{
FD_SET(sockfd, &outfd);
}
/* select() returns the number of signalled sockets or -1 */
res = select(sockfd + 1, &infd, &outfd, &errfd, &tv);
return res;
}
int main(void)
{
CURL *curl;
CURLcode res;
/* Minimalistic http request */
const char *request = "reactantsJSON={"O=O":{"N":1}}&productsJSON=["O=O","[O]"]&temperature=2273.15&pressure=101.325";
curl_socket_t sockfd; /* socket */
long sockextr;
size_t iolen;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://gibbs.sdsu.edu:8080/axis2/services/GibbsMinimization/solveTP");
/* Do not do the transfer - only connect to host */
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
res = curl_easy_perform(curl);
if(CURLE_OK != res)
{
printf("Error: %s\n", strerror(res));
return 1;
}
/* Extract the socket from the curl handle - we'll need it for waiting.
* Note that this API takes a pointer to a 'long' while we use
* curl_socket_t for sockets otherwise.
*/
res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockextr);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
sockfd = sockextr;
/* wait for the socket to become ready for sending */
if(!wait_on_socket(sockfd, 0, 60000L))
{
printf("Error: timeout.\n");
return 1;
}
puts("Sending request.");
/* Send the request. Real applications should check the iolen
* to see if all the request has been sent */
res = curl_easy_send(curl, request, strlen(request), &iolen);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
puts("Reading response.");
/* read the response */
for(;;)
{
char buf[1024];
wait_on_socket(sockfd, 1, 60000L);
res = curl_easy_recv(curl, buf, 1024, &iolen);
if(CURLE_OK != res)
break;
printf("Received %u bytes.\n", iolen);
}
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
the error I am getting is that it says a ";" is missing in line 40, which is nothing but the json string, even though I ahve a ";" on that line. It looks like to send json string i need to do something, which I am not aware of. Do I need to specify some flags while compiling the code.

const char *request = "reactantsJSON={"O=O":{"N":1}}&productsJSON=["O=O","[O]"]&temperature=2273.15&pressure=101.325";
You need to escape " in your string literal.
const char *request = "reactantsJSON={\"O=O\":{\"N\":1}}&productsJSON=[\"O=O\",\"[O]\"]&temperature=2273.15&pressure=101.325";

Related

Turning normal socket used by CURL into SSL socket in C

I'm dealing with code written by a 3rd party (which I don't want to radically change as I'll explain) which opens a tcp connection to talk json-rpc with a server. I want to add ssl to this as the server has an ssl port for the same comms. EDIT: I want to avoid using external proxies (like stunnel, which works).
Currently, the socket is opened by socket() and passed to curl via CURLOPT_OPENSOCKETFUNCTION and libcurl is told to stop after connecting (perform no data transfer) via CURLOPT_CONNECT_ONLY.
I tried enabling the SSL options in CURL starting with curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); but they had no effect, i.e. the connection itself succeeded in that the function connect() returned true (CURL was happy) but the data is still being sent unencrypted.
My understanding is: the socket is created externally (and passed to CURL which is told to not handle data transfer) and then written to directly, not via CURL or OpenSSL, so nothing actually encrypts the transfer ... despite enabling SSL in CURL.
I also tried to point CURL to https:// by doing sprintf(sctx->curl_url, "https%s", strstr(url, "://")); and then I get:
SSL: couldn't create a context: error:140A90A1:lib(20):func(169):reason(161)
I've also tried using OpenSSL directly on the opened socket, like here https://stackoverflow.com/a/41321247/1676217, by initializing OpenSSL and setting its file descriptor to sctx->sock which is the same socket passed to CURL (i.e. calling SSL_set_fd(ssl, sctx->sock);) but SSL_Connect() fails.
I can't change the code entirely to remove CURL or to remove the external socket creation as both are used in other parts of the code, though I can attempt to adapt it.
Basically, I'd like to keep the function declarations for thread_recv_line() and thread_send_line() and make them use SSL.
If anyone proficient with OpenSSL, CURL and/or sockets could show me how to do it within this code snippet, I'd be very grateful.
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#define socket_blocks() (errno == EAGAIN || errno == EWOULDBLOCK)
#define RBUFSIZE 2048
#define RECVSIZE (RBUFSIZE - 4)
struct ctx {
char *url;
CURL *curl;
char *curl_url;
char curl_err_str[CURL_ERROR_SIZE];
curl_socket_t sock;
size_t sockbuf_size;
char *sockbuf;
pthread_mutex_t sock_lock;
};
static curl_socket_t opensocket_grab_cb(void *clientp, curlsocktype purpose,
struct curl_sockaddr *addr)
{
curl_socket_t *sock = (curl_socket_t*) clientp;
*sock = socket(addr->family, addr->socktype, addr->protocol);
return *sock;
}
bool connect(struct ctx *sctx, const char *url)
{
CURL *curl;
int rc;
pthread_mutex_lock(&sctx->sock_lock);
if (sctx->curl)
curl_easy_cleanup(sctx->curl);
sctx->curl = curl_easy_init();
if (!sctx->curl) {
pthread_mutex_unlock(&sctx->sock_lock);
return false;
}
curl = sctx->curl;
if (!sctx->sockbuf) {
sctx->sockbuf = (char*) calloc(RBUFSIZE, 1);
sctx->sockbuf_size = RBUFSIZE;
}
sctx->sockbuf[0] = '\0';
pthread_mutex_unlock(&sctx->sock_lock);
if (url != sctx->url) {
free(sctx->url);
sctx->url = strdup(url);
}
free(sctx->curl_url);
sctx->curl_url = (char*) malloc(strlen(url));
sprintf(sctx->curl_url, "http%s", strstr(url, "://"));
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, sctx->curl_url);
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, sctx->curl_err_str);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1);
curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_keepalive_cb);
curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket_grab_cb);
curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &sctx->sock);
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1);
rc = curl_easy_perform(curl);
if (rc) {
curl_easy_cleanup(curl);
sctx->curl = NULL;
return false;
}
return true;
}
static bool send_line(curl_socket_t sock, char *s)
{
size_t sent = 0;
int len = (int) strlen(s);
s[len++] = '\n';
while (len > 0) {
struct timeval timeout = {0, 0};
int n;
fd_set wd;
FD_ZERO(&wd);
FD_SET(sock, &wd);
if (select((int) (sock + 1), NULL, &wd, NULL, &timeout) < 1)
return false;
n = send(sock, s + sent, len, 0);
if (n < 0) {
if (!socket_blocks())
return false;
n = 0;
}
sent += n;
len -= n;
}
return true;
}
bool thread_send_line(struct ctx *sctx, char *s)
{
bool ret = false;
pthread_mutex_lock(&sctx->sock_lock);
ret = send_line(sctx->sock, s);
pthread_mutex_unlock(&sctx->sock_lock);
return ret;
}
static bool socket_full(curl_socket_t sock, int timeout)
{
struct timeval tv;
fd_set rd;
FD_ZERO(&rd);
FD_SET(sock, &rd);
tv.tv_sec = timeout;
tv.tv_usec = 0;
if (select((int)(sock + 1), &rd, NULL, NULL, &tv) > 0)
return true;
return false;
}
static void buffer_append(struct ctx *sctx, const char *s)
{
size_t old, n;
old = strlen(sctx->sockbuf);
n = old + strlen(s) + 1;
if (n >= sctx->sockbuf_size) {
sctx->sockbuf_size = n + (RBUFSIZE - (n % RBUFSIZE));
sctx->sockbuf = (char*) realloc(sctx->sockbuf, sctx->sockbuf_size);
}
strcpy(sctx->sockbuf + old, s);
}
char *thread_recv_line(struct ctx *sctx)
{
ssize_t len, buflen;
char *tok, *sret = NULL;
if (!strstr(sctx->sockbuf, "\n")) {
bool ret = true;
time_t rstart;
time(&rstart);
if (!socket_full(sctx->sock, 60))
return sret;
do {
char s[RBUFSIZE];
ssize_t n;
memset(s, 0, RBUFSIZE);
n = recv(sctx->sock, s, RECVSIZE, 0);
if (!n) {
ret = false;
break;
}
if (n < 0) {
if (!socket_blocks() || !socket_full(sctx->sock, 1)) {
ret = false;
break;
}
} else
buffer_append(sctx, s);
} while (time(NULL) - rstart < 60 && !strstr(sctx->sockbuf, "\n"));
if (!ret)
return sret;
}
buflen = (ssize_t) strlen(sctx->sockbuf);
tok = strtok(sctx->sockbuf, "\n");
if (!tok)
return sret;
sret = strdup(tok);
len = (ssize_t) strlen(sret);
if (buflen > len + 1)
memmove(sctx->sockbuf, sctx->sockbuf + len + 1, buflen - len + 1);
else
sctx->sockbuf[0] = '\0';
}
This is not what you asked for, but you should consider placing a separate TCP-to-TLS proxy (such as HAProxy) between your code and remote server.
You will have to neither mess with TLS protocol details, nor modify existing code. Such setup will likely be safer and faster than anything you could write yourself.
Libcurl establishes an SSL connection with the server, even with CURLOPT_CONNECT_ONLY. It is not possible to establish another SSL connection on top of the same TCP connection. The only way to continue is to use the same SSL connection that libcurl has already established.
Fortunately it is possible to retrieve the SSL connection data from the curl handle using curl_easy_getinfo and CURLINFO_TLS_SSL_PTR. It should return a pointer of type SSL*.
The thread_send_line and thread_recv_line functions should not use the socket directly, but call SSL_read and SSL_write on the retrieved SSL pointer instead.
See CURLINFO_TLS_SSL_PTR for more information. Make sure you are getting an SSL pointer and not an SSL_CTX pointer.
Something like this should work:
bool thread_send_line(struct ctx *sctx, char *s)
{
bool ret = false;
struct curl_tlssessioninfo* session;
curl_easy_getinfo (sctx->curl, CURLINFO_TLS_SSL_PTR, &session);
SSL* ssl = session->internals;
pthread_mutex_lock(&sctx->sock_lock);
int len = (int) strlen(s);
s[len++] = '\n';
ret = SSL_write(ssl, s, len);
pthread_mutex_unlock(&sctx->sock_lock);
return ret == len;
}

Reading from named pipe freezes when piping tshark output

I'm trying to implement a web prefetching system. The purpose of a system like this is to “predict” future requests and prefetch them.
The system builds a predictive model from web navigation logs (Squid access.log files). The model is a dependency graph, where a node representing URL A has an arc to a node representing URL B if URL B has been requested immediately after URL A.
Once the model is built, the system receives queries of URLs requested by users, and make “predictions” based on the graph. Predictions are resources (URLs) very likely to be requested in the future. So, based on predictions, the system prefetches these resources to store them in cache prior to users' requests.
I'm using the following testing scenario:
A process simulate multiple clients, requesting URLs in a file using libcurl. The process runs in a different PC from the prefetching system. PCs are connected directly via an ethernet cable
Requests made by the client simulator are always the same URLs in the same relative time from the first request made. All requests are going to port 3128 (Prefetch PC Squid listen port) (port 80 DNAT to port 3128 in the client).
The prefetching system runs in a CentOS 6.3 box, kernel 2.6.32-71.el6.i686, 2 core Intel Pentium 4 3.00GHz processor, 4 GB RAM.
The prefetching system is one process with multiple threads. The main thread creates the predictive model and generates predictions based on queries. A “listener” thread reads URLs requested by users and prefetches predicted URLs using libcurl. “Listening” means reading from a named pipe (called url_fifo) URLs captured live on an interface using tshark:
stdbuf -o0 tshark -i eth1 tcp port 3128 and "tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420" -T fields -e http.request.full_uri >> url_fifo
Each 10 minutes (1 cycle) the model is updated based on requests from the last cycle. The client tells the system when a cycle ends and so the model is updated. Once the model is updated, the system tells the client to start requesting URLs from the next cycle.
Here is the situation: Sometimes reading from the named pipe freezes. No URLs are read from the pipe even though tshark keeps capturing URLs and redirecting them to the named pipe. After an hour (or a couple of hours) all “buffered” URLs are read in less than 10 minutes. After that, reading from the pipe keeps going ok again. This situation doesn't happen always (50% of times freezes, 50% no).
It seems that there is a buffering issue, since tshark keeps capturing URLs and all requests are correctly logged in Squid's access.log.
In the beginning, I ran tshark with the -l option, so that its output becomes line buffered. Then I started using stdbuf -o0 (no buffering). Anyway the situation still happens.
In the system code, I also tried opening and reading the named pipe as a stream (FILE *) and set the stream as no buffered or line buffered (using setvbuf() function). The situation still happened.
In some cycles requests are faster than in other cycles. Anyway, it doesn't seems to be a fast producer slow consumer issue, since in many repetitions of the test all URLs are correctly read and processed without any freezes.
Is there something am I missing related to named pipes and buffering? I'd really appreciate some guidance.
Assume networking (interfaces, routing, iptables, squid) is ok. I've not had any issues related to it.
Code (assume necessary header files are included):
functions.c
#define BUFLEN 512
#define QUEUE_LEN 64
#define THREADS_LEN 2
pthread_mutex_t model_lock;
pthread_cond_t model_cond, listen_cond;
pthread_t queries_thread, listen_thread;
short int model_is_updating, model_can_update, program_shutdown;
/* Program execution statistics */
Status * program_status;
/* Thread pool */
threadpool_t *pool;
/* program execution */
int
run(void)
{
Graph_Adj_List * gr = NULL; /* Graph as an adjacency list */
char ** reports = NULL;
unsigned report_counter = 0;
/* Init program status */
program_status = status_init();
/* Load list of custom web navigation reports to be used to build the initial
* version of the predictive model */
reports = file_load_reports(program_config.reports_file);
if (!reports)
return 0;
/* Init mutex and cond */
pthread_mutex_init(&model_lock, NULL);
pthread_cond_init(&model_cond, NULL);
pthread_cond_init(&listen_cond, NULL);
/* Lock */
pthread_mutex_lock (&model_lock);
/* Start first cycle */
status_start_cycle(program_status);
/* Create initial version of the predictive model */
gr = create_model_from_files(reports, &report_counter, program_config.reports_limit);
if (!gr)
{
/* Unlock */
pthread_mutex_unlock (&model_lock);
return 0;
}
/* Unlock */
pthread_mutex_unlock (&model_lock);
/* Start threads */
if (pthread_create(&queries_thread, NULL, fifo_predictions_threaded, (void *)gr) ||
pthread_create(&listen_thread, NULL, listen_end_of_cycle, NULL))
program_shutdown = 1;
/* main loop */
while(!program_shutdown)
{
/* lock */
pthread_mutex_lock (&model_lock);
/* wait for clients' announcement of the end of requests from current cycle */
while (!model_can_update)
pthread_cond_wait(&model_cond, &model_lock);
/* set updating flag */
model_is_updating = 1;
/* Update predictive model, based on Squid's access.log from (about to finish)
* current cycle */
adj_list_update_access(gr, program_config.access_file);
/* Save statistics related to the current cycle and finish it */
status_finish_cycle(program_status);
/* Check if last custom report has been read */
if (!reports[report_counter])
{
program_shutdown = 1;
pthread_mutex_unlock (&model_lock);
break;
}
/* Start a new cycle */
status_start_cycle(program_status);
/* Read a new custom report and update the predictive model */
update_model(gr, reports[report_counter]);
report_counter++;
/* Updating is done */
model_is_updating = 0;
/* Model can't be updated until client announces the end of the cycle
* that has just started */
model_can_update = 0;
/* Tell client to start sending requests from the new cycle */
if (!signal_start_cycle())
{
program_shutdown = 1;
pthread_mutex_unlock (&model_lock);
break;
}
/* Signal listener thread that a new cycle has begin */
pthread_cond_signal(&listen_cond);
/* Unlock */
pthread_mutex_unlock (&model_lock);
}
/* Finish threads */
pthread_cancel(listen_thread);
pthread_cancel(queries_thread);
pthread_join(listen_thread, NULL);
pthread_join(queries_thread, NULL);
/* Free memory */
adj_list_free_all2(&gr);
file_reports_free_all(&reports);
pthread_cond_destroy(&model_cond);
pthread_cond_destroy(&listen_cond);
pthread_mutex_destroy(&model_lock);
status_free(&program_status);
return 1;
}
void *
fifo_predictions_threaded(void * data)
{
Graph_Adj_List * gr = (Graph_Adj_List *) data;
/* Set thread cancel type */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while (!program_shutdown)
{
pthread_mutex_lock(&model_lock);
/* Pause reading from named pipe while the model is being updated */
while(model_is_updating)
pthread_cond_wait(&listen_cond, &model_lock);
pthread_mutex_unlock(&model_lock);
/* Read URLs from named pipe */
fifo_predictions(gr, program_config.fifo);
}
pthread_exit(NULL);
return NULL;
}
int
fifo_predictions(Graph_Adj_List * gr, const u8 * fifo)
{
u8 cad[BUFLEN] = { '\0' };
u8 * ini = NULL, * fin = NULL, * fullurl = NULL;
int i, fifo_descriptor, read_urls = 0, fullurl_len = 0, incomplete_url = 1;
FILE * fifo_file = NULL;
/* Open fifo in blocking mode */
fifo_descriptor = open(CHAR_CAST fifo, O_RDONLY);
/* Open fifo as a stream */
// fifo_file = fopen(fifo, "r");
// if (!fifo_file)
if (fifo_descriptor == -1)
return 0;
/* If fifo is opened as a stream, set it line buffered */
// setlinebuf(fifo_file);
do
{
if ((i = read(fifo_descriptor, cad, BUFLEN - 1)) == -1)
// if ( fgets(cad, BUFLEN-1, fifo_file) == NULL)
ERROR(__FILE__, __FUNCTION__, __LINE__, "Fifo read error");
else
{
// i = strlen(cad);
cad[i] = '\0';
read_urls = 0;
if (i > 0)
{
int j = 0;
for (j = 0, ini = cad, fin = NULL ; cad[j] != '\0'; j++)
{
if (cad[j] == '\n')
{
/* Save URL */
fin = &cad[j];
ini = (*ini == '\n' ? ini + 1 : ini);
/* Check if string is a continuation of the previously read URL */
read_urls = fin - ini;
read_urls = read_urls >= 0 ? read_urls : 0;
/* Save URL in fullurl string */
fullurl = realloc(fullurl, fullurl_len + read_urls + 1);
memcpy(&fullurl[fullurl_len], ini, read_urls);
fullurl[fullurl_len + read_urls] = '\0';
ini = fin;
incomplete_url = fullurl_len = 0;
/* Ask the model for predictions and fetch them */
fetch_url_predictions2(gr, fullurl);
u8_free(&fullurl);
} else
incomplete_url = 1;
}
if (incomplete_url)
{
ini = (*ini == '\n' ? ini + 1 : ini);
read_urls = &cad[j] - ini;
read_urls = read_urls >= 0 ? read_urls : 0;
fullurl = realloc(fullurl, fullurl_len + read_urls);
memcpy(&fullurl[fullurl_len], ini, read_urls);
fullurl_len += read_urls;
}
}
}
} while (i > 0);
close(fifo_descriptor);
// fclose (fifo_file);
return 1;
}
int
fetch_url_predictions2(Graph_Adj_List * gr, u8 * in_url)
{
String * string_url = NULL;
Headnode * head = NULL;
LinkedList * list = NULL;
LinkedListElem * elem = NULL;
/* Use custom string type */
string_url = string_create_no_len(in_url);
if (!string_url)
return 0;
pthread_mutex_lock(&model_lock);
/* Get URL node */
head = adj_list_get_node(gr, string_url);
if (head)
{
/* Get predictions (URLs) as a linked list */
list = adj_list_predictions_to_list(head);
if (!list)
{
string_free_all(&string_url);
return 0;
}
pthread_mutex_unlock(&model_lock);
/* Callback fetches URLs */
list->callback = &curl_callback_void;
if (!pool)
pool = threadpool_create(THREADS_LEN, QUEUE_LEN, 0);
/* Load URLs to be fetched to threadpool's task queue */
for (elem = list->first; elem; elem = elem->next)
{
CallbackArg arg;
arg.data = arg.copy(elem->data);
threadpool_add_copy_arg(pool, list->callback, &arg, 1, sizeof(arg), 0);
}
linked_list_free_all(&list);
}
pthread_mutex_unlock(&model_lock);
string_free_all(&string_url);
return 1;
}
fetch.c
void
curl_callback_void(void * data)
{
CallbackArg * arg = (CallbackArg *) data;
char * url = (char *) arg->data;
fetch_url(url);
}
static size_t
write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
return size * nmemb;
}
int
fetch_url(char * url)
{
CURL *curl;
CURLcode res;
struct timeval time;
char * time_string = NULL;
curl = curl_easy_init();
if (curl)
{
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
gettimeofday(&time, NULL);
time_string = timeval_to_str(&time);
/* Check for errors */
if (res != CURLE_OK)
{
fprintf(stderr, "\ntime %s curl_easy_perform() (url %s) failed: %s\n",
time_string, url, curl_easy_strerror(res));
}
else
{
fprintf(stderr, "\ntime %s curl_easy_perform() (url %s) fetched ok\n",
time_string, url);
}
fflush(stderr);
free (time_string);
curl_easy_cleanup(curl);
}
return 0;
}
network.c
/*
* Code based on Beej's Networking Guide
*/
#define MSG_LEN 5
#define QUEUE_SIZE 5
extern pthread_mutex_t model_lock;
extern pthread_cond_t model_cond;
extern short int model_can_update, program_shutdown;
extern Config program_config;
// get sockaddr, IPv4 or IPv6:
static void *
get_in_addr(struct sockaddr *sa) {
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*) sa)->sin_addr);
}
return &(((struct sockaddr_in6*) sa)->sin6_addr);
}
void *
listen_end_of_cycle(void * data)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
int yes = 1;
char s[INET_ADDRSTRLEN], msg[MSG_LEN], *str = NULL;
int rv;
int read_bytes;
struct timeval actual_time;
/* Set thread cancel type */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, program_config.listen_port, &hints, &servinfo))
!= 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return "error";
}
// loop through all the results and bind to the first we can
for (p = servinfo; p != NULL ; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol))
== -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))
== -1) {
perror("setsockopt");
return "error";
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL ) {
fprintf(stderr, "server: failed to bind\n");
return "error";
}
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, QUEUE_SIZE) == -1) {
perror("listen");
return "error";
}
while (!program_shutdown)
{
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *) &their_addr), s, sizeof s);
if ((read_bytes = recv(new_fd, msg, MSG_LEN - 1, 0)) == -1) {
perror("recv");
continue;
}
close(new_fd);
msg[read_bytes] = '\0';
/* Check received message */
if (strcmp(msg, "DONE")) {
perror("Not valid message");
continue;
}
printf("\ngot \"DONE\" from %s\n", s);
fflush(stdout);
/* Lock */
pthread_mutex_lock(&model_lock);
/* Flag used by main thread to allow model update */
model_can_update = 1;
/* Signal model can be updated */
pthread_cond_signal(&model_cond);
/* Unlock */
pthread_mutex_unlock(&model_lock);
}
close(sockfd);
pthread_exit(NULL);
return "ok";
}
int signal_start_cycle(void) {
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN], *str = NULL;
struct timeval actual_time, aux_time;
struct timeval connect_timeout = { 15, 0 }, max_connect_time = { 0, 0 };
short int connected = 0;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(program_config.client_ip, program_config.client_port,
&hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 0;
}
gettimeofday(&aux_time, NULL);
timeval_add(aux_time, connect_timeout, &max_connect_time);
/* Try several times to connect to the remote side */
do {
// loop through all the results and connect to the first we can
for (p = servinfo; p != NULL ; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol))
== -1) {
perror("client: socket");
continue;
}
gettimeofday(&actual_time, NULL )
printf("\ntrying to connect %s\n", program_config.client_ip);
fflush(stdout);
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: connect");
continue;
}
connected = 1;
break;
}
} while (!connected && !timeval_greater_than(actual_time, max_connect_time));
if (p == NULL ) {
fprintf(stderr, "client: failed to connect\n");
return 0;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *) p->ai_addr), s,
sizeof s);
printf("\nMAIN THREAD: connecting to %s\n", s);
fflush(stdout);
freeaddrinfo(servinfo); // all done with this structure
if (send(sockfd, "DONE", 4, 0) == -1)
{
perror("send");
return 0;
}
printf("\nsent \"DONE\" to %s\n", s);
fflush(stdout);
close(sockfd);
return 1;
}

Building SOAP request using libcurl

Below is my code for building a SOAP request:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* Auxiliary function that waits on the socket. */
static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms)
{
struct timeval tv;
fd_set infd, outfd, errfd;
int res;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec= (timeout_ms % 1000) * 1000;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
FD_SET(sockfd, &errfd); /* always check for error */
if(for_recv)
{
FD_SET(sockfd, &infd);
}
else
{
FD_SET(sockfd, &outfd);
}
/* select() returns the number of signalled sockets or -1 */
res = select(sockfd + 1, &infd, &outfd, &errfd, &tv);
return res;
}
int main(void)
{
CURL *ch;
CURLcode res;
struct curl_slist *headerlist=NULL;
struct MemoryStruct *bodyStruct=NULL;
char _gatineauSoapReq[2000]="";
const char *WriteMemoryCallback;
/* Minimalistic http request */
curl_socket_t sockfd; /* socket */
long sockextr;
size_t iolen;
ch = curl_easy_init();
curl_easy_setopt(ch, CURLOPT_URL, "http://thermo.sdsu.edu/servlet/ThermodynamicProperties/ThermodynamicPropertiesService");
curl_easy_setopt(ch, CURLOPT_POST, 1);
curl_easy_setopt(ch, CURLOPT_HEADER, 1);
curl_easy_setopt(ch, CURLOPT_VERBOSE, 1);
curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
if ((bodyStruct = (struct MemoryStruct *) malloc(sizeof(struct MemoryStruct))) == NULL) exit(1);
curl_easy_setopt(ch, CURLOPT_FILE, bodyStruct);
curl_slist_free_all(headerlist);
headerlist = curl_slist_append(headerlist, "Content-Type: text/xml");
headerlist = curl_slist_append(headerlist, "SOAPAction: \"http://blabla.com/blabla_services/ValidateNow\"");
sprintf(_gatineauSoapReq, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:getSpeciesInformationResponse
xmlns:ns2="http://ThermodynamicProperties/">
<return>
{"Nist":true,"Abinitio":[["3-21G","MP2",""]],"Nasa":true,"Chemkin":true,"Burcat":true}
</return>
</ns2:getSpeciesInformationResponse>
</S:Body>
</S:Envelope>
curl_easy_setopt(ch, CURLOPT_POSTFIELDS, _gatineauSoapReq);
curl_easy_setopt(ch, CURLOPT_HTTPHEADER, headerlist);
curl_easy_perform(ch);
//res = curl_easy_perform(curl);
if(CURLE_OK != res)
{
printf("Error: %s\n", strerror(res));
return 1;
}
/* Extract the socket from the curl handle - we'll need it for waiting.
* Note that this API takes a pointer to a 'long' while we use
* curl_socket_t for sockets otherwise.
*/
res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockextr);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
sockfd = sockextr;
/* wait for the socket to become ready for sending */
if(!wait_on_socket(sockfd, 0, 60000L))
{
printf("Error: timeout.\n");
return 1;
}
puts("Sending request.");
/* Send the request. Real applications should check the iolen
* to see if all the request has been sent */
//res = curl_easy_send(curl,, strlen(request), &iolen);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
puts("Reading response.");
/* read the response */
//for(;;)
{
printf("ok1 \n");
char buf[1024];
wait_on_socket(sockfd, 1, 60000L);
res = curl_easy_recv(curl, buf, 1024, &iolen);
printf("ok2 \n");
if(CURLE_OK != res)
//break;
printf("Error: %s\n", strerror(res));
//printf("ok3 \n");
//printf("Received %u bytes.\n", iolen);
printf("data %s \n", buf);
}
/* always cleanup */
curl_easy_cleanup(curl);
return 0;
}
Also along with building the SOAP request, how should one send the request, should we use the curl_easy_send().
I am getting the following error:
curls.c: In function âmainâ:
curls.c:57:45: warning: incompatible implicit declaration of built-in function âmallocâ
curls.c:57:59: error: invalid application of âsizeofâ to incomplete type âstruct MemoryStructâ
curls.c:57:91: warning: incompatible implicit declaration of built-in function âexitâ
curls.c:63:72: warning: backslash and newline separated by space
curls.c:64:22: error: expected â)â before âhttpâ
curls.c:69:60: error: invalid suffix "G" on integer constant
curls.c:146:1: error: expected â;â before â}â token
It seems you have syntax mistakes or missing declarations - have a look at the error lines you provide from your log.

Not able to read data using libcurl

Below is my code:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* Auxiliary function that waits on the socket. */
static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms)
{
struct timeval tv;
fd_set infd, outfd, errfd;
int res;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec= (timeout_ms % 1000) * 1000;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
FD_SET(sockfd, &errfd); /* always check for error */
if(for_recv)
{
FD_SET(sockfd, &infd);
}
else
{
FD_SET(sockfd, &outfd);
}
/* select() returns the number of signalled sockets or -1 */
res = select(sockfd + 1, &infd, &outfd, &errfd, &tv);
return res;
}
int main(void)
{
CURL *curl;
CURLcode res;
/* Minimalistic http request */
const char *request = "reactantsJSON={\"O=O\":{\"N\":1}}&productsJSON=[\"O=O\",\"[O]\"]&temperature=2273.15&pressure=101.325";
curl_socket_t sockfd; /* socket */
long sockextr;
size_t iolen;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://gibbs.sdsu.edu:8080/axis2/services/GibbsMinimization/solveTP");
/* Do not do the transfer - only connect to host */
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
res = curl_easy_perform(curl);
if(CURLE_OK != res)
{
printf("Error: %s\n", strerror(res));
return 1;
}
/* Extract the socket from the curl handle - we'll need it for waiting.
* Note that this API takes a pointer to a 'long' while we use
* curl_socket_t for sockets otherwise.
*/
res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockextr);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
sockfd = sockextr;
/* wait for the socket to become ready for sending */
if(!wait_on_socket(sockfd, 0, 60000L))
{
printf("Error: timeout.\n");
return 1;
}
puts("Sending request.");
/* Send the request. Real applications should check the iolen
* to see if all the request has been sent */
res = curl_easy_send(curl, request, strlen(request), &iolen);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
puts("Reading response.");
/* read the response */
for(;;)
{
char buf[1024];
wait_on_socket(sockfd, 1, 60000L);
res = curl_easy_recv(curl, buf, 1024, &iolen);
if(CURLE_OK != res)
break;
printf("Received %u bytes.\n", iolen);
}
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
I am sending a Json string and the response I am expecting is an XML document. When I compile my code it compiles without errors. But for some reason it is not going in the for loop for the receive function. Any kind of help would be appreciated. thanks in advance.
$ gdb ./a.out
GNU gdb (GDB) 7.2-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from a.out...done.
(gdb) b 98
Breakpoint 1 at 0x400f5d: file c.c, line 98.
(gdb) run
Starting program: a.out
[Thread debugging using libthread_db enabled]
Sending request.
Reading response.
Breakpoint 1, main () at c.c:99
99 if(CURLE_OK != res)
(gdb) p res
$1 = CURLE_UNSUPPORTED_PROTOCOL
(gdb)
you have to put everything after the 1st slash in request instead of in curl_easy_setopt, so
curl_easy_setopt(curl, CURLOPT_URL, "http://gibbs.sdsu.edu:8080");
and
const char *request = "GET /axis2/services/GibbsMinimization/solveTP?reactantsJSON={\"O=O\":{\"N\":1}}&productsJSON=[\"O=O\",\"[O]\"]&temperature=2273.15&pressure=101.325 HTTP/1.0\r\n\r\n";
cause of you're doing the http request manually
also, way to initialize buf with all zeroes is
char buf[1024]={0};

Sending SOAP request using libcurl

I could understand the examples of simple sendrecv for sending REST request using libcurl. Now i want to send a SOAP request using libcurl. I have changed the REST request code to achieve the same, but the code is not working. My code is:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* Auxiliary function that waits on the socket. */
static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms)
{
struct timeval tv;
fd_set infd, outfd, errfd;
int res;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec= (timeout_ms % 1000) * 1000;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
FD_SET(sockfd, &errfd); /* always check for error */
if(for_recv)
{
FD_SET(sockfd, &infd);
}
else
{
FD_SET(sockfd, &outfd);
}
/* select() returns the number of signalled sockets or -1 */
res = select(sockfd + 1, &infd, &outfd, &errfd, &tv);
return res;
}
int main(void)
{
CURL *curl;
CURLcode res;
/* Minimalistic http request */
const char *request = "<?xml version="1.0" encoding="utf-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://ThermodynamicProperties/">
<S:Body>
<tns:getSpeciesInformation>
<speciesSymbol>CO2</speciesSymbol>
<phase>GAS</phase>
</tns:getSpeciesInformation>
</S:Body>
</S:Envelope>";
curl_socket_t sockfd; /* socket */
long sockextr;
size_t iolen;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://thermo.sdsu.edu/servlet/ThermodynamicProperties/ThermodynamicPropertiesService");
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request);
/* Do not do the transfer - only connect to host */
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
res = curl_easy_perform(curl);
if(CURLE_OK != res)
{
printf("Error: %s\n", strerror(res));
return 1;
}
/* Extract the socket from the curl handle - we'll need it for waiting.
* Note that this API takes a pointer to a 'long' while we use
* curl_socket_t for sockets otherwise.
*/
res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockextr);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
sockfd = sockextr;
/* wait for the socket to become ready for sending */
if(!wait_on_socket(sockfd, 0, 60000L))
{
printf("Error: timeout.\n");
return 1;
}
puts("Sending request.");
/* Send the request. Real applications should check the iolen
* to see if all the request has been sent */
res = curl_easy_send(curl,request, strlen(request), &iolen);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
I feel that I am not doing correct in building the SOAP request. Any help would be great as this is a completely new field for me.
SOAP messages are much more complex than REST messages.
My advice would be to download one of the better SOAP utilities like "SOAPUI" and use this to build and test a well formed SOAP request. Once you have a working request you can paste this into your C program.
Also I would recommend using a library like libxml2 (or Xerces if you dont mind C++) to build your SOAP messages if you are doing anything more complex than sending a simple pre formatted request.
SOAPUI is a java based test utility SOAP services. It can generate messages form a given WSDL, generate responses, browse messages etc.
More info here: SOAPUI

Resources