Hi Bogdan/Liviu,

I have downloaded 2.1.4 version if opensips and trying to use rest_put call in 
async mode.

I have added the necessary code for rest_put () similar to rest_post() in 
rest_methods.c, rest_methods.h and rest_client.c
If I just call, rest_put from config file, without async it works fine. I could 
see rest_put() is called and do the necessary steps.

And am trying to call async from config file as,
 async(rest_put("http://***url*** <http://***url***%20> ", "$fU,$tU,$ci ", 
"application/json", "$var(body)", "$var(ct)", "$var(rcode)"),resume_put);

Further debugging I got some info that I can share with you so that you can 
help me out easily.
Instead of calling rest_put asynchronously I have tried to call rest_post async 
. I could able to see that HTTP request went out(from wireshark traces) and I 
got 4xx response for the same.

With my code changes in place and when I call rest_put, am not seeing HTTP 
request sent out.
Assuming rest_put only is not working, there should be some libcurl stuffs not 
handled properly in 'start_async_http_req' for 'REST_CLIENT_PUT' case.

Am attaching the files. It contains code for rest_put only. I have removed 
other code to reduce the file size. Can you please take a look guide me here.
Please let me know if you need more information on this.

Regards,
Agalya


From: [email protected] 
[mailto:[email protected]] On Behalf Of Liviu Chircu
Sent: Friday, August 05, 2016 4:47 AM
To: [email protected]
Subject: Re: [OpenSIPS-Users] Asynchronous operation for REST queries

Hi Agalya,

1.11 has no async support at core level. If you need that, you will have to use 
2.1+

Async rest_put() is currently not implemented, but its logic would be fairly 
similar to the GET and POST counterparts.


Liviu Chircu

OpenSIPS Developer

http://www.opensips-solutions.com
On 04.08.2016 23:14, Ramachandran, Agalya (Contractor) wrote:
Hi team,

We are using opensips1.11.3 version for our project.
I have a question here. Right now we are using a REST API call from config file 
for our project requirement and it is in synchronous mode currently.
>From the opensips document, I see asynchronous support at script level can be 
>done in 2.1 version.
Is it possible to change in asynchronous mode in 1.11 version?
If not, is there a way to achieve asynchronous REST calls for the version of 
opensips what we are using?

Also I see from documentation,

The following functions may also be called asynchronously:

  *   
avp_db_query<http://www.opensips.org/html/docs/modules/2.1.x/avpops.html#id294986>
  *   
rest_get<http://www.opensips.org/html/docs/modules/2.1.x/rest_client.html#id293741>
  *   
rest_post<http://www.opensips.org/html/docs/modules/2.1.x/rest_client.html#id293886>
  *   exec<http://www.opensips.org/html/docs/modules/2.1.x/exec#id294052>
Can rest_put can also be called asynchronously if we use 2.1 version ?
Please clarify.

Regards,
Agalya




_______________________________________________

Users mailing list

[email protected]<mailto:[email protected]>

http://lists.opensips.org/cgi-bin/mailman/listinfo/users

/*
 * Copyright (C) 2013-2015 OpenSIPS Solutions
 *
 * This file is part of opensips, a free SIP server.
 *
 * opensips is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version
 *
 * opensips is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * History:
 * -------
 * 2013-02-28: Created (Liviu)
 */


#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>

#include "../../async.h"
#include "../../sr_module.h"
#include "../../dprint.h"
#include "../../mem/mem.h"
#include "../../mem/shm_mem.h"
#include "../../mod_fix.h"

#include "rest_methods.h"

/*
 * Module parameters
 */
long connection_timeout = 20;
long connection_timeout_ms;
long curl_timeout = 20;

char *ssl_capath;

/* libcurl enables these by default */
int ssl_verifypeer = 1;
int ssl_verifyhost = 1;

/*
 * Module initialization and cleanup
 */
static int mod_init(void);
static int child_init(int rank);
static void mod_destroy(void);

/*
 * Fixup functions
 */
static int fixup_rest_get(void **param, int param_no);
static int fixup_rest_post(void **param, int param_no);
static int fixup_rest_put(void **param, int param_no);

/*
 * Function headers
 */
static int w_rest_get(struct sip_msg *msg, char *gp_url, char *body_pv,
                                char *ctype_pv, char *code_pv);
static int w_rest_post(struct sip_msg *msg, char *gp_url, char *gp_body,
                                char *gp_ctype, char *body_pv, char *ctype_pv, 
char *code_pv);
static int w_rest_put(struct sip_msg *msg, char *gp_url, char *gp_body,
                                char *gp_ctype, char *body_pv, char *ctype_pv, 
char *code_pv);

static int w_async_rest_get(struct sip_msg *msg, async_resume_module **resume_f,
                                                        void **resume_param, 
char *gp_url,
                                                        char *body_pv, char 
*ctype_pv, char *code_pv);
static int w_async_rest_post(struct sip_msg *msg, async_resume_module 
**resume_f,
                                         void **resume_param, char *gp_url, 
char *gp_body,
                                         char *gp_ctype, char *body_pv, char 
*ctype_pv, char *code_pv);
static int w_async_rest_put(struct sip_msg *msg, async_resume_module **resume_f,
                                         void **resume_param, char *gp_url, 
char *gp_body,
                                         char *gp_ctype, char *body_pv, char 
*ctype_pv, char *code_pv);



static acmd_export_t acmds[] = {
        { "rest_get",  (acmd_function)w_async_rest_get,  2, fixup_rest_get },
        { "rest_get",  (acmd_function)w_async_rest_get,  3, fixup_rest_get },
        { "rest_get",  (acmd_function)w_async_rest_get,  4, fixup_rest_get },
        { "rest_post", (acmd_function)w_async_rest_post, 4, fixup_rest_post },
        { "rest_post", (acmd_function)w_async_rest_post, 5, fixup_rest_post },
        { "rest_post", (acmd_function)w_async_rest_post, 6, fixup_rest_post },
        { "rest_put",  (acmd_function)w_async_rest_put,  4, fixup_rest_put },
        { "rest_put",  (acmd_function)w_async_rest_put,  5, fixup_rest_put },
        { "rest_put",  (acmd_function)w_async_rest_put,  6, fixup_rest_put },
        { 0, 0, 0, 0 }
};

/*
 * Exported functions
 */
static cmd_export_t cmds[] = {
        { "rest_get",(cmd_function)w_rest_get, 2, fixup_rest_get, 0,
                REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|
                ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE },
        { "rest_get",(cmd_function)w_rest_get, 3, fixup_rest_get, 0,
                REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|
                ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE },
        { "rest_get",(cmd_function)w_rest_get, 4, fixup_rest_get, 0,
                REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|
                ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE },
        { "rest_post",(cmd_function)w_rest_post, 4, fixup_rest_post, 0,
                REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|
                ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE },
        { "rest_post",(cmd_function)w_rest_post, 5, fixup_rest_post, 0,
                REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|
                ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE },
        { "rest_post",(cmd_function)w_rest_post, 6, fixup_rest_post, 0,
                REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|
                ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE },
         { "rest_put",(cmd_function)w_rest_put, 4, fixup_rest_put, 0,
                REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|
                ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE },
        { "rest_put",(cmd_function)w_rest_put, 5, fixup_rest_put, 0,
                REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|
                ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE },
        { "rest_put",(cmd_function)w_rest_put, 6, fixup_rest_put, 0,
                REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|
                ONREPLY_ROUTE|STARTUP_ROUTE|TIMER_ROUTE },

        { 0, 0, 0, 0, 0, 0 }
};


/*
 * Exported parameters
 */
static param_export_t params[] = {
        { "connection_timeout", INT_PARAM, &connection_timeout  },
        { "curl_timeout",               INT_PARAM, &curl_timeout                
},
        { "ssl_capath",                 STR_PARAM, &ssl_capath                  
},
        { "ssl_verifypeer",             INT_PARAM, &ssl_verifypeer              
},
        { "ssl_verifyhost",             INT_PARAM, &ssl_verifyhost              
},
        { 0, 0, 0 }
};


/*
 * Module parameter variables
 */
struct module_exports exports = {
        "rest_client",
        MOD_TYPE_DEFAULT,/* class of this module */
        MODULE_VERSION,  /* module version */
        DEFAULT_DLFLAGS, /* dlopen flags */
        NULL,            /* OpenSIPS module dependencies */
        cmds,     /* Exported functions */
        acmds,    /* Exported async functions */
        params,   /* Exported parameters */
        NULL,     /* exported statistics */
        NULL,     /* exported MI functions */
        NULL,     /* exported pseudo-variables */
        NULL,     /* extra processes */
        mod_init, /* module initialization function */
        NULL,     /* response function*/
        mod_destroy,
        child_init,/* per-child init function */
};

static void *osips_malloc(size_t size)
{
        void *p = pkg_malloc(size);

        return p;
}

static void *osips_calloc(size_t nmemb, size_t size)
{
        void *p = pkg_malloc(nmemb * size);
        if (p)
                memset(p, '\0', nmemb * size);

        return p;
}

static void *osips_realloc(void *ptr, size_t size)
{
        void *p = pkg_realloc(ptr, size);

        return p;
}

static char *osips_strdup(const char *cp)
{
        char *rval;
        int len;

        len = strlen(cp) + 1;
        rval = pkg_malloc(len);
        if (!rval)
                return NULL;

        memcpy(rval, cp, len);
        return rval;
}

static void osips_free(void *ptr)
{
        if (ptr)
                pkg_free(ptr);
}

static int mod_init(void)
{
        LM_DBG("Initializing...\n");

        connection_timeout_ms = connection_timeout * 1000L;

        curl_global_init_mem(CURL_GLOBAL_ALL,
                                                 osips_malloc,
                                                 osips_free,
                                                 osips_realloc,
                                                 osips_strdup,
                                                 osips_calloc);

        multi_handle = curl_multi_init();

        LM_INFO("Module initialized!\n");

        return 0;
}

static int child_init(int rank)
{
        if (rank <= PROC_MAIN)
                return 0;

        multi_handle = curl_multi_init();
        if (!multi_handle) {
                LM_ERR("failed to init CURLM handle\n");
                return -1;
        }

        return 0;
}

static void mod_destroy(void)
{
        curl_global_cleanup();
}

/**************************** Fixup functions *******************************/

static int fixup_rest_put(void **param, int param_no)
{
        switch (param_no) {
        case 1:
        case 2:
        case 3:
                return fixup_spve(param);
        case 4:
        case 5:
        case 6:
                return fixup_pvar(param);

        default:
                LM_ERR("Too many parameters!\n");
                return -1;
        }
}


/**************************** Module functions *******************************/


static int w_rest_put(struct sip_msg *msg, char *gp_url, char *gp_body,
                   char *gp_ctype, char *body_pv, char *ctype_pv, char *code_pv)
{
        str url, body, ctype = { NULL, 0 };

        if (fixup_get_svalue(msg, (gparam_p)gp_url, &url) != 0) {
                LM_ERR("Invalid HTTP URL pseudo variable!\n");
                return -1;
        }

        if (fixup_get_svalue(msg, (gparam_p)gp_body, &body) != 0) {
                LM_ERR("Invalid HTTP POST body pseudo variable!\n");
                return -1;
        }

        if (gp_ctype && fixup_get_svalue(msg, (gparam_p)gp_ctype, &ctype) != 0) 
{
                LM_ERR("Invalid HTTP POST content type pseudo variable!\n");
                return -1;
        }

        return rest_put_method(msg, url.s, body.s, ctype.s, (pv_spec_p)body_pv,
                                (pv_spec_p)ctype_pv, (pv_spec_p)code_pv);
}


static void set_output_pv_params(struct sip_msg *msg, str *body_in, pv_spec_p 
body_pv, str *ctype_in,
                                                                 pv_spec_p 
ctype_pv, CURL *handle, pv_spec_p code_pv)
{
        pv_value_t val;
        long http_rc;
        CURLcode rc;

        val.flags = PV_VAL_STR;
        val.rs = *body_in;

        if (pv_set_value(msg, (pv_spec_p)body_pv, 0, &val) != 0)
                LM_ERR("failed to set output body pv\n");

        if (ctype_pv) {
                val.rs = *ctype_in;
                if (pv_set_value(msg, (pv_spec_p)ctype_pv, 0, &val) != 0)
                        LM_ERR("failed to set output ctype pv\n");
        }

        if (code_pv) {
                rc = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, 
&http_rc);
                if (rc != CURLE_OK)
                        LM_ERR("curl_easy_getinfo: %s\n", 
curl_easy_strerror(rc));

                LM_DBG("Last response code: %ld\n", http_rc);

                val.flags = PV_VAL_INT|PV_TYPE_INT;
                val.ri = (int)http_rc;
                if (pv_set_value(msg, (pv_spec_p)code_pv, 0, &val) != 0)
                        LM_ERR("failed to set output code pv\n");
        }
}



static int w_async_rest_put(struct sip_msg *msg, async_resume_module **resume_f,
                                         void **resume_param, char *gp_url, 
char *gp_body,
                                         char *gp_ctype, char *body_pv, char 
*ctype_pv, char *code_pv)
{
        rest_async_param *param;
        str url, body, ctype = { NULL, 0 };
        int read_fd;

        if (fixup_get_svalue(msg, (gparam_p)gp_url, &url) != 0) {
                LM_ERR("Invalid HTTP URL pseudo variable!\n");
                return -1;
        }

        if (fixup_get_svalue(msg, (gparam_p)gp_body, &body) != 0) {
                LM_ERR("Invalid HTTP POST body pseudo variable!\n");
                return -1;
        }

        if (gp_ctype && fixup_get_svalue(msg, (gparam_p)gp_ctype, &ctype) != 0) 
{
                LM_ERR("Invalid HTTP POST content type pseudo variable!\n");
                return -1;
        }

        LM_DBG("async rest put '%.*s' %p %p %p\n", url.len, url.s, body_pv, 
ctype_pv, code_pv);
         param = pkg_malloc(sizeof *param);
        if (!param) {
                LM_ERR("no more shm\n");
                return -1;
        }
        memset(param, '\0', sizeof *param);

        read_fd = start_async_http_req(msg, REST_CLIENT_PUT, url.s, body.s, 
ctype.s,
                                &param->handle, &param->body, ctype_pv ? 
&param->ctype : NULL);

        /* error occurred; no transfer done */
        if (read_fd == ASYNC_NO_IO) {
                *resume_param = NULL;
                *resume_f = NULL;
                /* keep default async status of NO_IO */
                return -1;

        /* no need for async - transfer already completed! */
        } else if (read_fd == ASYNC_SYNC) {
                set_output_pv_params(msg, &param->body, (pv_spec_p)body_pv,
                                                         &param->ctype, 
(pv_spec_p)ctype_pv,
                                                         param->handle, 
(pv_spec_p)code_pv);

                pkg_free(param->body.s);
                if (ctype_pv && param->ctype.s)
                        pkg_free(param->ctype.s);
                curl_easy_cleanup(param->handle);
                pkg_free(param);

                return ASYNC_SYNC;
        }

        *resume_f = resume_async_http_req;

        param->method = REST_CLIENT_PUT;
        param->body_pv = (pv_spec_p)body_pv;
        param->ctype_pv = (pv_spec_p)ctype_pv;

        param->code_pv = (pv_spec_p)code_pv;
        *resume_param = param;
        /* async started with success */
        async_status = read_fd;

        return 1;
}


/*
 * Copyright (C) 2013 OpenSIPS Solutions
 *
 * This file is part of opensips, a free SIP server.
 *
 * opensips is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version
 *
 * opensips is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * History:
 * -------
 * 2013-02-28: Created (Liviu)
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>

#include "../../mem/shm_mem.h"
#include "../../async.h"
#include "rest_methods.h"
#include "rest_cb.h"

static char print_buff[MAX_CONTENT_TYPE_LEN];

CURLM *multi_handle;

/* simultaneous ongoing transfers within this process */
static int transfers;
static int read_fds[FD_SETSIZE];

/* libcurl's reported running handles */
static int running_handles;

static long sleep_on_bad_timeout = 500; /* ms */


#define clean_header_list(list) \
        do { \
                if (list) { \
                        curl_slist_free_all(list); \
                        list = NULL; \
                } \
        } while (0)

#define w_curl_easy_setopt(h, opt, value) \
        do { \
                rc = curl_easy_setopt(h, opt, value); \
                if (rc != CURLE_OK) { \
                        LM_ERR("curl_easy_setopt(%d): (%s)\n", opt, 
curl_easy_strerror(rc)); \
                        goto cleanup; \
                } \
        } while (0)

static inline char is_new_transfer(int fd)
{
        int it;

        for (it = 0; it < transfers; it++) {
                if (fd == read_fds[it])
                        return 0;
        }

        return 1;
}

static inline void add_transfer(int fd)
{
        read_fds[transfers++] = fd;
}

static inline char del_transfer(int fd)
{
        int it;

        LM_DBG("del fd %d\n", fd);

        for (it = 0; it < transfers; it++) {
                if (fd == read_fds[it]) {
                        transfers--;
                        for (; it < transfers; it++)
                                read_fds[it] = read_fds[it + 1];

                        return 0;
                }
        }

        return -1;
}

int generateRandomNumber()
{
   srand ( time(NULL) );
   int random_number = rand();
   int rand_capped = random_number % 1000;
   //LM_INFO("Random Number Generated: %d\n", rand_capped);
   return rand_capped;
}


/**
 * start_async_http_req - performs an HTTP request, stores results in pvars
 *              - TCP connect phase is synchronous, due to libcurl limitations
 *              - TCP read phase is asynchronous, thanks to the libcurl multi 
interface
 *
 * @msg:                sip message struct
 * @method:             HTTP verb
 * @url:                HTTP URL to be queried
 * @req_body:   Body of the request (NULL if not needed)
 * @req_ctype:  Value for the "Content-Type: " header of the request (same as ^)
 * @out_handle: CURL easy handle used to perform the transfer
 * @body:           reply body; gradually reallocated as data arrives
 * @ctype:          will eventually hold the last "Content-Type" header of the 
reply
 */
int start_async_http_req(struct sip_msg *msg, enum rest_client_method method,
                                             char *url, char *req_body, char 
*req_ctype,
                                             CURL **out_handle, str *body, str 
*ctype)
{
        CURL *handle;
        CURLcode rc;
        CURLMcode mrc;
        struct curl_slist *list = NULL;
        fd_set rset, wset, eset;
        int max_fd, fd, i;
        long busy_wait, timeout;
        long retry_time, check_time = 5; /* 5ms looping time */
        int msgs_in_queue;
        CURLMsg *cmsg;

        if (transfers == FD_SETSIZE) {
                LM_ERR("too many ongoing tranfers: %d\n", FD_SETSIZE);
                clean_header_list(list);
                return ASYNC_NO_IO;
        }

        handle = curl_easy_init();
        if (!handle) {
                LM_ERR("Init curl handle failed!\n");
                clean_header_list(list);
                return ASYNC_NO_IO;
        }

        w_curl_easy_setopt(handle, CURLOPT_URL, url);

        switch (method) {
        case REST_CLIENT_POST:
                w_curl_easy_setopt(handle, CURLOPT_POST, 1);
                w_curl_easy_setopt(handle, CURLOPT_POSTFIELDS, req_body);

                if (req_ctype) {
                        sprintf(print_buff, "Content-Type: %s", req_ctype);
                        list = curl_slist_append(list, print_buff);
                        w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, list);
                }
                break;
        case REST_CLIENT_PUT:
                w_curl_easy_setopt(handle, CURLOPT_PUT, 1);
                w_curl_easy_setopt(handle, CURLOPT_POSTFIELDS, req_body);

                if (req_ctype) {
                        sprintf(print_buff, "Content-Type: %s", req_ctype);
                        list = curl_slist_append(list, print_buff);
                        w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, list);
                }
                break;
        case REST_CLIENT_GET:
                break;

        default:
                LM_ERR("Unsupported rest_client_method: %d, defaulting to 
GET\n", method);
        }

        w_curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, connection_timeout);
        w_curl_easy_setopt(handle, CURLOPT_TIMEOUT, curl_timeout);

        w_curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
        w_curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1);
        w_curl_easy_setopt(handle, CURLOPT_STDERR, stdout);

        w_curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func);
        w_curl_easy_setopt(handle, CURLOPT_WRITEDATA, body);

        if (ctype) {
                w_curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, header_func);
                w_curl_easy_setopt(handle, CURLOPT_HEADERDATA, ctype);
        }

        if (ssl_capath)
                w_curl_easy_setopt(handle, CURLOPT_CAPATH, ssl_capath);

        if (!ssl_verifypeer)
                w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);

        if (!ssl_verifyhost)
                w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);

        curl_multi_add_handle(multi_handle, handle);

        timeout = connection_timeout_ms;
        /* obtain a read fd in "connection_timeout" seconds at worst */
        for (timeout = connection_timeout_ms; timeout > 0; timeout -= 
busy_wait) {
                mrc = curl_multi_perform(multi_handle, &running_handles);
                if (mrc != CURLM_OK) {
                        LM_ERR("curl_multi_perform: %s\n", 
curl_multi_strerror(mrc));
                        goto error;
                }

                mrc = curl_multi_timeout(multi_handle, &retry_time);
                if (mrc != CURLM_OK) {
                        LM_ERR("curl_multi_timeout: %s\n", 
curl_multi_strerror(mrc));
                        goto error;
                }

                if (retry_time == -1) {
                        LM_INFO("curl_multi_timeout() returned -1, pausing 
%ldms...\n",
                                        sleep_on_bad_timeout);
                        busy_wait = sleep_on_bad_timeout;
                        usleep(1000UL * busy_wait);
                        continue;
                }

                busy_wait = retry_time < timeout ? retry_time : timeout;

                /**
                 * libcurl is currently stuck in internal operations (connect)
                 *    we have to wait a bit until we receive a read fd
                 */
                for (i = 0; i < busy_wait; i += check_time) {
                        /* transfer may have already been completed!! */
                        while ((cmsg = curl_multi_info_read(multi_handle, 
&msgs_in_queue))) {
                                if (cmsg->easy_handle == handle && cmsg->msg == 
CURLMSG_DONE) {
                                        LM_DBG("done, no need for async!\n");

                                        clean_header_list(list);
                                        *out_handle = handle;
                                        return ASYNC_SYNC;
                                }
                        }

                        FD_ZERO(&rset);
                        mrc = curl_multi_fdset(multi_handle, &rset, &wset, 
&eset, &max_fd);
                        if (mrc != CURLM_OK) {
                                LM_ERR("curl_multi_fdset: %s\n", 
curl_multi_strerror(mrc));
                                goto error;
                        }

                        if (max_fd != -1) {
                                for (fd = 0; fd <= max_fd; fd++) {
                                        if (FD_ISSET(fd, &rset)) {

                                                LM_DBG(" >>>>>>>>>> fd %d 
ISSET(read)\n", fd);
                                                if (is_new_transfer(fd)) {
                                                        LM_DBG("add fd to read 
list: %d\n", fd);
                                                        add_transfer(fd);
                                                        goto success;
                                                }
                                        }
                                }
                        }

                        usleep(1000UL * check_time);
                }
        }

        LM_ERR("timeout while connecting to '%s' (%ld sec)\n", url, 
connection_timeout);
        goto error;

success:
        clean_header_list(list);
        *out_handle = handle;
        return fd;

error:
        mrc = curl_multi_remove_handle(multi_handle, handle);
        if (mrc != CURLM_OK)
                LM_ERR("curl_multi_remove_handle: %s\n", 
curl_multi_strerror(mrc));

cleanup:
        clean_header_list(list);
        curl_easy_cleanup(handle);
        return ASYNC_NO_IO;
}


/**
 * rest_put_method - performs an HTTP POST request, stores results in pvars
 * @msg:                sip message struct
 * @url:                HTTP URL to be queried
 * @ctype:              Value for the "Content-Type: " header of the request
 * @body:               Body of the request
 * @body_pv:    pseudo var which will hold the result body
 * @ctype_pv:   pvar which will hold the result content type
 * @code_pv:    pvar to hold the HTTP return code
 */
int rest_put_method(struct sip_msg *msg, char *url, char *body, char *ctype,
                     pv_spec_p body_pv, pv_spec_p ctype_pv, pv_spec_p code_pv)
{
        LM_INFO("URL : %s", url);
        CURLcode rc;
        CURL *handle = NULL;
        long http_rc;
        struct curl_slist *list = NULL;
        str st = { 0, 0 };
        str res_body = { NULL, 0 }, tbody;
        str dst_uri = { 0, 0 };
        pv_value_t pv_val;
        char reqbody[1000] = "";
        char temp_buff[1000] = "";
        char resturl[1000] = "";
        char *fromuri=NULL, *touri=NULL, *instanceId=NULL;
        int randValue=0;
        char *temp_str = NULL;


        handle = curl_easy_init();
        if (!handle) {
                LM_ERR("Init curl handle failed!\n");
                return -1;
        }

        char Body[1000] = "";
        sprintf(Body, "%s", body);

        char Ctype[1000] = "";
        sprintf(Ctype, "%s", ctype);


        fromuri = strtok(Body, ",");
        touri = strtok(NULL, ",");
        instanceId = strtok(NULL, ",");

        temp_str = "trace-id=";
        char *xtrace = (char*)malloc(1+strlen(temp_str)+strlen(instanceId));
        strcpy(xtrace,temp_str);
        strcat(xtrace,instanceId);

        if (ctype) {
                sprintf(temp_buff, "Content-Type: %s", Ctype);
                list = curl_slist_append(list, temp_buff);
                sprintf(temp_buff, "Uid: %s", &fromuri[2]);
                list = curl_slist_append(list, temp_buff);
                sprintf(temp_buff, "serviceId: tel");
                list = curl_slist_append(list, temp_buff);
                sprintf(temp_buff, "custguid: %s", instanceId);
                list = curl_slist_append(list, temp_buff);
                randValue = generateRandomNumber();
                sprintf(temp_buff, "x-tracking-id: %d", randValue );
                list = curl_slist_append(list, temp_buff);
                sprintf(temp_buff, "X-Trace: %s", xtrace );
                list = curl_slist_append(list, temp_buff);
                list = curl_slist_append(list, "x-server-name: RTCGSM");
                list = curl_slist_append(list, "x-client-name: IMS");
                list = curl_slist_append(list, "x-source-id: OpenSIP");
                list = curl_slist_append(list, "user-agent: OpenSIPv1.11.3");
                sprintf(temp_buff, "device-id: %s", instanceId );
                list = curl_slist_append(list, temp_buff);
                w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, list);

        }

        sprintf(resturl, "%suid=%s&custguid=%s", url, &fromuri[2],  instanceId);


        LM_INFO("**fromuri: %s, touri: %s, instanceId: %s, Xtrace: %s, REST 
request url: %s", &fromuri[2], &touri[2], instanceId,               
xtrace,resturl);
        w_curl_easy_setopt(handle, CURLOPT_URL, resturl);
        w_curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "PUT");

        /*Populating request payload*/
        sprintf(reqbody, 
"{\"participantsInfo\":[\"%s\"],\"callType\":\"audio\",\"instanceId\":\"%s\",\"fromUID\":\"%s\",\"fromTN\":\"%s\",\"isOpenSipRequest\":%s,\"displayName\":\"Call
 From 
IMS\",\"deviceType\":\"Android/iOS/STB/IMS\"}",&touri[2],instanceId,&fromuri[2],&fromuri[2],"true");

        LM_INFO("*Actual rest request payload (JSON):jsonPayload= 
%s\n",reqbody);


        w_curl_easy_setopt(handle, CURLOPT_POSTFIELDS, reqbody);
         w_curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, connection_timeout);
        w_curl_easy_setopt(handle, CURLOPT_TIMEOUT, curl_timeout);

        w_curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
        w_curl_easy_setopt(handle, CURLOPT_STDERR, stdout);
        w_curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1);

        w_curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func);
        w_curl_easy_setopt(handle, CURLOPT_WRITEDATA, &res_body);

        w_curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, header_func);
        w_curl_easy_setopt(handle, CURLOPT_HEADERDATA, &st);

        if (ssl_capath)
                w_curl_easy_setopt(handle, CURLOPT_CAPATH, ssl_capath);

        if (!ssl_verifypeer)
                w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);

        if (!ssl_verifyhost)
                w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);

        rc = curl_easy_perform(handle);
        clean_header_list(list);

        if (code_pv) {
                curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_rc);
                LM_DBG("Last response code: %ld\n", http_rc);

                pv_val.flags = PV_VAL_INT|PV_TYPE_INT;
                pv_val.ri = (int)http_rc;

                if (pv_set_value(msg, code_pv, 0, &pv_val) != 0) {
                        LM_ERR("Set code pv value failed!\n");
                        goto cleanup;
                }
        }

        if (rc != CURLE_OK) {
                LM_ERR("curl_easy_perform: %s\n", curl_easy_strerror(rc));
                goto cleanup;
        }

        tbody = res_body;
        trim(&tbody);

        pv_val.flags = PV_VAL_STR;
        pv_val.rs = tbody;

        LM_INFO("*: Actual result body is: jsonPayload= %s\n", res_body.s);


         char tempstring[1000] = "";
        sprintf(tempstring, "%s", res_body.s);

        char *token = NULL;

        char respstring[1000] = "";
        sprintf(respstring, "%s", res_body.s);


        token = NULL;
        token = strtok(respstring, ",");
        token = strtok(NULL, ",");
        token = strtok(NULL, ",");

        char mucAndJigassi[1000] = "";
        char muc[1000] = "";
        char jigasiIp[1000] = "";
        char jigasiFQDN[1000] = "";

        sprintf(mucAndJigassi, "%s", token);

        token = NULL;
        token = strtok(&mucAndJigassi[9], "@");
        sprintf(muc, "%s", token);
        token = strtok(NULL, "@");
        token = strtok(token, "\"");
        sprintf(jigasiIp, "%s", token);

        sprintf(jigasiFQDN, "sip:%s:5060", jigasiIp);
        dst_uri.s = jigasiFQDN;
        dst_uri.len = strlen(dst_uri.s);



        if (set_dst_uri(msg, &dst_uri) < 0) {
                LM_ERR("error while setting dst uri\n");
                goto cleanup;
        }

        sprintf(pv_val.rs.s, "%s", muc);
        pv_val.rs.len = strlen(pv_val.rs.s);

        if (pv_set_value(msg, body_pv, 0, &pv_val) != 0) {
                LM_ERR("Set body pv value failed!\n");
                goto cleanup;
        }

        if (res_body.s) {
                pkg_free(res_body.s);
        }

        if (ctype_pv) {
                pv_val.rs = st;

                if (pv_set_value(msg, ctype_pv, 0, &pv_val) != 0) {
                        LM_ERR("Set content type pv value failed!\n");
                        goto cleanup;
                }

                if (st.s)
                        pkg_free(st.s);
        }

        curl_easy_cleanup(handle);
        return 1;

cleanup:
        clean_header_list(list);
          curl_easy_cleanup(handle);
        return -1;
}
/*
 * Copyright (C) 2013 OpenSIPS Solutions
 *
 * This file is part of opensips, a free SIP server.
 *
 * opensips is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version
 *
 * opensips is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * History:
 * -------
 * 2013-02-28: Created (Liviu)
 */

#ifndef _REST_METHODS_
#define _REST_METHODS_

#include "../../pvar.h"
#include "../../dprint.h"
#include "../../error.h"
#include "../../mem/mem.h"

extern CURLM *multi_handle;

extern long connection_timeout;
extern long connection_timeout_ms;
extern long curl_timeout;

extern char *ssl_capath;
extern int ssl_verifypeer;
extern int ssl_verifyhost;

/* Currently supported HTTP verbs */
enum rest_client_method {
        REST_CLIENT_GET,
        REST_CLIENT_POST,
        REST_CLIENT_PUT
};

typedef struct rest_async_param_ {
        enum rest_client_method method;
        CURL *handle;
        str body;
        str ctype;

        pv_spec_p body_pv;
        pv_spec_p ctype_pv;
        pv_spec_p code_pv;
} rest_async_param;

int rest_get_method(struct sip_msg *msg, char *url,
                    pv_spec_p body_pv, pv_spec_p ctype_pv, pv_spec_p code_pv);
int rest_post_method(struct sip_msg *msg, char *url, char *body, char *ctype,
                     pv_spec_p body_pv, pv_spec_p ctype_pv, pv_spec_p code_pv);
int rest_put_method(struct sip_msg *msg, char *url, char *body, char *ctype,
                     pv_spec_p body_pv, pv_spec_p ctype_pv, pv_spec_p code_pv);

int start_async_http_req(struct sip_msg *msg, enum rest_client_method method,
                                             char *url, char *req_body, char 
*req_ctype,
                                             CURL **out_handle, str *body, str 
*ctype);
enum async_ret_code resume_async_http_req(int fd, struct sip_msg *msg, void 
*param);

#endif /* _REST_METHODS_ */

_______________________________________________
Users mailing list
[email protected]
http://lists.opensips.org/cgi-bin/mailman/listinfo/users

Reply via email to