3
\$\begingroup\$

First of all, I would like to know if there is any difference (execution-time) in C between:

  • GET request made by using cURL
  • GET request make by using sockets (BSD sockets)

Second, I've done a C program which parses a XML file (without using any xml-specific library) and makes a GET request with the parsed info as it follows:

http://www.example.com/k=content1|content2|content3
http://www.example.com/k=content4|content5|content6
and so on...

My XML file looks like this:

<tag1>
<tag2>
  <Server>
    <Host>content1</Host>
    <User>content2</User>
    <Pass encoding="base64">content3</Pass>
  </Server>
  <Server>
    <Host>content4</Host>
    <User>content5</User>
    <Pass encoding="base64">content6</Pass>
  </Server>
  <Server>
    <Host>content7</Host>
    <User>content8</User>
    <Pass encoding="base64">content9</Pass>
  </Server>
</tag2>
</tag1>

My code uses just one function as this is how I want it done (without any parameter). Could you please answer my first question and provide some improvements / advices regarding my code ? ( what would you do / use / delete ). I would like to get a response regarding the GET requests then anything else if possible.

The code:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <curl/curl.h>
#define keyurl "http://www.link.com"
int getKeyVal(char *key);
// return data from the server
struct return_string {
    char *ptr;
    size_t len;
};
// utility functions
size_t accumulate(void *ptr, size_t size, size_t nmemb, struct return_string *s);
void init_string(struct return_string *s);
/* get the <key> */
int getKeyVal(char *key)
{
    CURL *curl;
    CURLcode res;
    char url[128];
    sprintf(url, "%s/k=%s", keyurl, key);
    curl = curl_easy_init();
    if (curl) {
        struct return_string s;
        init_string(&s);
        curl_easy_setopt(curl, CURLOPT_URL, keyurl);
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, accumulate);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
        res = curl_easy_perform(curl);
        printf("result: %s\n", s.ptr);
        free(s.ptr);
        curl_easy_cleanup(curl);
    }
    else {
        res = -99;
    }
    return(res);
}
/* Initialize the string handler so that it is thread safe */
void init_string(struct return_string *s)
{
    s->len = 0;
    s->ptr = malloc(s->len + 1);
    if (s->ptr == NULL) {
        fprintf(stderr, "malloc() failed\n");
        exit(-1);
    }
    s->ptr[0] = '\0';
}
/* Use the "writer" to accumulate text until done */
size_t accumulate(void *ptr, size_t size, size_t nmemb, struct return_string *s)
{
    size_t new_len = s->len + size*nmemb;
    s->ptr = realloc(s->ptr, new_len + 1);
    if (s->ptr == NULL) {
        fprintf(stderr, "realloc() failed\n");
        exit(-1);
    }
    memcpy(s->ptr + s->len, ptr, size*nmemb);
    s->ptr[new_len] = '\0';
    s->len = new_len;
    return size*nmemb;
}
int getContent()
{
    //constants for reading the XML file
    char *buffer = 0;
    char finalRequest[200];
    long length;
    FILE *xmlFile = fopen("C:/Users/IEUser/Desktop/rs.xml", "r");
    //constants for parsing XML
    const char *HOSTSTART = "<Host>";
    const char *HOSTEND = "</Host>";
    const char *USERSTART = "<User>";
    const char *USEREND = "</User>";
    const char *PASSSTART = "<Pass encoding=\"base64\">";
    const char *PASSEND = "</Pass>";
    char *target_host = NULL, *target_user = NULL, *target_pass = NULL, *start, *end;
    //read the xml file
    if (xmlFile)
    {
        fseek(xmlFile, 0, SEEK_END);
        length = ftell(xmlFile);
        fseek(xmlFile, 0, SEEK_SET);
        buffer = malloc(length);
        if (buffer)
        {
            fread(buffer, 1, length, xmlFile);
        }
        fclose(xmlFile);
        if (!buffer) exit(1);
    }
    start = buffer;
    while (1) {
        //get the HOST
        if (start = strstr(start, HOSTSTART))
        {
            start += strlen(HOSTSTART);
            if (end = strstr(start, HOSTEND))
            {
                target_host = (char *)malloc(end - start + 1);
                memcpy(target_host, start, end - start);
                target_host[end - start] = '\0';
            }
        }
        else {
            break;
        }
        //get the USER
        if (start = strstr(start, USERSTART))
        {
            start += strlen(USERSTART);
            if (end = strstr(start, USEREND))
            {
                target_user = (char *)malloc(end - start + 1);
                memcpy(target_user, start, end - start);
                target_user[end - start] = '\0';
            }
        }
        //get the PASS
        if (start = strstr(start, PASSSTART))
        {
            start += strlen(PASSSTART);
            if (end = strstr(start, PASSEND))
            {
                target_pass = (char *)malloc(end - start + 1);
                memcpy(target_pass, start, end - start);
                target_pass[end - start] = '\0';
            }
        }
        //send the requested string in the desired format to finalRequest[]
        //k=host|user|password
        strcpy(finalRequest, target_host);
        strcat(finalRequest, "|");
        strcat(finalRequest, target_user);
        strcat(finalRequest, "|");
        strcat(finalRequest, target_pass);
        printf("%s", finalRequest);
        printf("\n\n");
        getKeyVal(finalRequest);
    }
    return 0;
}
int main()
{
    getContent();
    return 0;
}
\$\endgroup\$
  • 2
    \$\begingroup\$ A start would be timing both options multiple times. \$\endgroup\$ – Mast Jul 7 '15 at 10:05
  • \$\begingroup\$ As Mast put it, there's only one way to find out. There are many variables in such a broad statement. It could vary by architecture, network, kernel etc. \$\endgroup\$ – jacwah Jul 7 '15 at 10:23
  • \$\begingroup\$ Any speed benefit of either would be dwarfed by the latency of the connection, surely. Propagation delay across a network connection, even a local one ? \$\endgroup\$ – mckenzm Jul 7 '15 at 12:39
1
\$\begingroup\$

Don't use forward declarations of functions when you don't need to. If the parameters change, you have to edit two locations in your code. The only time when you actually need them is when two functions both reference each other.

Improve the readability of your code by putting newlines in-between unrelated parts of the code. For instance, between function definitions and between definitions and blocks of #includes. I also like putting newlines before and after ifs and loops.

I expect a function called getX to return data to the caller, either through return value or pointer parameter. Niether getKeyVal or getContent follow this expectation. getKeyVal could be called sendRequest, which would better describe it's behavior because it doesn't return a key/value pair.

I would refactor getContent to actually return finalRequest and then call getKeyVal/sendRequest from main with it. Have one function that does one thing, not one function that calls everything else (that's what main is for!).

\$\endgroup\$
  • \$\begingroup\$ could you please be more specific about the first and the second advices ? I've noted the second one and will update the final version as I will get it fully done. \$\endgroup\$ – Grajdeanu Alex. Jul 7 '15 at 11:11
  • \$\begingroup\$ @Alex You've put int getKeyVal(char *key); etc at the top of your code. This doesn't serve any purpose and the compiler will complain if you change one of the declarations of getKeyVal but forget the other. \$\endgroup\$ – jacwah Jul 7 '15 at 11:17
  • \$\begingroup\$ Ouh, you're right. I completely missed this. Will remove it. What about the last point ? \$\endgroup\$ – Grajdeanu Alex. Jul 7 '15 at 11:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.