Search code examples
c++curlsoapwebservices-client

Listen to a push message?


I have to listen to a web service’s push message indefinitely. The web service I am listening to send soap response messages whenever there is an update in the content. After I received the message I have to parse it and store it in to structs. Following is my code.

CURL *curl;
CURLcode res;
const char *onlineWebServiceRequest = "<?xml version=\"1.0\" encoding=\"utf-8\"?> <soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">  <soap:Body>    <GetCitiesByCountry xmlns=\"http://www.webserviceX.NET\">  <CountryName>Netherlands</CountryName>     </GetCitiesByCountry>    </soap:Body>    </soap:Envelope>";

if(curl){

    curl_easy_setopt(curl, CURLOPT_URL, "http://www.webservicex.net/globalweather.asmx/GetCitiesByCountry" );

    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, onlineWebServiceRequest);  

    res = curl_easy_perform(curl);       
    // call some other method to parse the res
    curl_easy_cleanup(curl);    
} 

Doubts: Is it the right way to receive push messages? If yes.,

The above code does not check the connection status with web service. How can I check that?

If no, what are all the other option I have probably with open source?

Thanks in advance


Solution

  • You'd better off checking for errors.

    To do that you have to enable CURLOPT_ERRORBUFFER option.

    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
    

    And add a buffer (it must be at least CURL_ERROR_SIZE bytes big).

    char errbuf[CURL_ERROR_SIZE];
    

    Additionally, you could set CURLOPT_FAILONERROR to true, to force curl to convert all response codes >= 300 to errors.

    curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
    

    To get the actual output from the server you need to set a function to write the data (CURLOPT_WRITEFUNCTION) and a chunk of memory (CURLOPT_WRITEDATA).

    A complete example adapted from [1] and [2]:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <curl/curl.h>
    
    struct MemoryStruct {
      char *memory;
      size_t size;
    };
    
    static size_t
    WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
    {
      size_t realsize = size * nmemb;
      struct MemoryStruct *mem = (struct MemoryStruct *)userp;
    
      mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
      if(mem->memory == NULL) {
        /* out of memory! */ 
        printf("not enough memory (realloc returned NULL)\n");
        return 0;
      }
    
      memcpy(&(mem->memory[mem->size]), contents, realsize);
      mem->size += realsize;
      mem->memory[mem->size] = 0;
    
      return realsize;
    }
    
    int main(void)
    {
      curl_global_init(CURL_GLOBAL_ALL);
    
      /* init the curl session */ 
      CURL curl = curl_easy_init();
      if(curl) {
        CURLcode res;
    
        struct MemoryStruct chunk;
    
        chunk.memory = (char *)malloc(1);  /* will be grown as needed by the realloc above */ 
        chunk.size = 0;    /* no data at this point */ 
    
        char errbuf[CURL_ERROR_SIZE];
    
        /* specify URL to get */ 
        curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
    
        /* send all data to this function  */ 
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
    
        /* we pass our 'chunk' struct to the callback function */ 
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
    
        /* force curl to fail error when http code >= 300 */
        curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
    
        /* provide a buffer to store errors in */
        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
    
        /* set the error buffer as empty before performing a request */
        errbuf[0] = 0;
    
        /* perform the request */
        res = curl_easy_perform(curl);
    
        /* if the request did not complete correctly, show the error
        information. if no detailed error information was written to errbuf
        show the more generic information from curl_easy_strerror instead.
        */
        if(res != CURLE_OK) {
          size_t len = strlen(errbuf);
          fprintf(stderr, "\nlibcurl: (%d) ", res);
          if(len)
            fprintf(stderr, "%s%s", errbuf,
                    ((errbuf[len - 1] != '\n') ? "\n" : ""));
          else
            fprintf(stderr, "%s\n", curl_easy_strerror(res));
        }
        else {
          /*
           * Now, our chunk.memory points to a memory block that is chunk.size
           * bytes big and contains the remote file.
           *
           * Do something nice with it!
           */ 
    
          printf("%lu bytes retrieved\n", (long)chunk.size);
        }
    
        /* cleanup curl stuff */ 
        curl_easy_cleanup(curl);
    
        free(chunk.memory);
    
      }
    
      /* we're done with libcurl, so clean it up */ 
      curl_global_cleanup();
    
      return 0;
    }