mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
632 lines
17 KiB
632 lines
17 KiB
/**
|
|
* Copyright 2016 (C) Federico Cabiddu <federico.cabiddu@gmail.com>
|
|
* Copyright 2016 (C) Giacomo Vacca <giacomo.vacca@gmail.com>
|
|
* Copyright 2016 (C) Orange - Camille Oudot <camille.oudot@orange.com>
|
|
*
|
|
* This file is part of Kamailio, a free SIP server.
|
|
*
|
|
* This file 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
|
|
*
|
|
*
|
|
* This file 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
/*! \file
|
|
* \brief Kamailio http_async_client :: multi interface
|
|
* \ingroup http_async_client
|
|
*/
|
|
|
|
|
|
#include "../../dprint.h"
|
|
#include "../../mem/mem.h"
|
|
#include "../../ut.h"
|
|
#include "../../hashes.h"
|
|
#include "http_multi.h"
|
|
|
|
extern int hash_size;
|
|
/*! global http multi table */
|
|
struct http_m_table *hm_table = 0;
|
|
struct http_m_global *g = 0;
|
|
|
|
/* 0: shm, 1:system malloc */
|
|
int curl_memory_manager = 0;
|
|
|
|
/* Update the event timer after curl_multi library calls */
|
|
int multi_timer_cb(CURLM *multi, long timeout_ms, struct http_m_global *g)
|
|
{
|
|
struct timeval timeout;
|
|
(void)multi; /* unused */
|
|
|
|
timeout.tv_sec = timeout_ms/1000;
|
|
timeout.tv_usec = (timeout_ms%1000)*1000;
|
|
LM_DBG("multi_timer_cb: Setting timeout to %ld ms\n", timeout_ms);
|
|
evtimer_add(g->timer_event, &timeout);
|
|
return 0;
|
|
}
|
|
/* Called by libevent when our timeout expires */
|
|
void timer_cb(int fd, short kind, void *userp)
|
|
{
|
|
struct http_m_global *g = (struct http_m_global *)userp;
|
|
CURLMcode rc;
|
|
(void)fd;
|
|
(void)kind;
|
|
|
|
char error[CURL_ERROR_SIZE];
|
|
|
|
LM_DBG("timeout on socket %d\n", fd);
|
|
|
|
rc = curl_multi_socket_action(g->multi,
|
|
CURL_SOCKET_TIMEOUT, 0, &g->still_running);
|
|
if (check_mcode(rc, error) < 0) {
|
|
LM_ERR("curl_multi_socket_action error: %s", error);
|
|
}
|
|
|
|
check_multi_info(g);
|
|
}
|
|
/* Called by libevent when we get action on a multi socket */
|
|
void event_cb(int fd, short kind, void *userp)
|
|
{
|
|
struct http_m_global *g;
|
|
CURLMcode rc;
|
|
CURL *easy = (CURL*) userp;
|
|
struct http_m_cell *cell;
|
|
|
|
cell = http_m_cell_lookup(easy);
|
|
if (cell == NULL) {
|
|
LM_INFO("Cell for handler %p not found in table\n", easy);
|
|
return;
|
|
}
|
|
|
|
g = cell->global;
|
|
int action =
|
|
(kind & EV_READ ? CURL_CSELECT_IN : 0) |
|
|
(kind & EV_WRITE ? CURL_CSELECT_OUT : 0);
|
|
|
|
LM_DBG("activity %d on socket %d: action %d\n", kind, fd, action);
|
|
if (kind == EV_TIMEOUT) {
|
|
LM_DBG("handle %p timeout on socket %d (cell=%p, param=%p)\n", cell->easy, fd, cell, cell->param);
|
|
update_stat(timeouts, 1);
|
|
const char *error = "TIMEOUT";
|
|
|
|
strncpy(cell->error, error, strlen(error)+1);
|
|
|
|
reply_error(cell);
|
|
|
|
easy = cell->easy;
|
|
/* we are going to remove the cell and the handle here:
|
|
pass NULL as sockptr */
|
|
curl_multi_assign(g->multi, cell->sockfd, NULL);
|
|
|
|
LM_DBG("cleaning up cell %p\n", cell);
|
|
if (cell->evset && cell->ev) {
|
|
LM_DBG("freeing event %p\n", cell->ev);
|
|
event_del(cell->ev);
|
|
event_free(cell->ev);
|
|
cell->ev=NULL;
|
|
cell->evset=0;
|
|
}
|
|
unlink_http_m_cell(cell);
|
|
free_http_m_cell(cell);
|
|
|
|
LM_DBG("removing handle %p\n", easy);
|
|
curl_multi_remove_handle(g->multi, easy);
|
|
curl_easy_cleanup(easy);
|
|
rc = curl_multi_socket_action(g->multi,
|
|
CURL_SOCKET_TIMEOUT, 0, &g->still_running);
|
|
|
|
} else {
|
|
LM_DBG("performing action %d on socket %d\n", action, fd);
|
|
rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running);
|
|
LM_DBG("action %d on socket %d performed\n", action, fd);
|
|
|
|
if (rc == CURLM_CALL_MULTI_PERFORM) {
|
|
LM_DBG("received CURLM_CALL_MULTI_PERFORM, performing action again\n");
|
|
rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running);
|
|
}
|
|
if (check_mcode(rc, cell->error) < 0) {
|
|
LM_ERR("error: %s\n", cell->error);
|
|
reply_error(cell);
|
|
curl_multi_remove_handle(g->multi, easy);
|
|
curl_easy_cleanup(easy);
|
|
}
|
|
}
|
|
|
|
check_multi_info(g);
|
|
if ( g->still_running <= 0 ) {
|
|
LM_DBG("last transfer done, kill timeout\n");
|
|
if (evtimer_pending(g->timer_event, NULL)) {
|
|
evtimer_del(g->timer_event);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* CURLMOPT_SOCKETFUNCTION */
|
|
int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp)
|
|
{
|
|
struct http_m_global *g = (struct http_m_global*) cbp;
|
|
struct http_m_cell *cell = (struct http_m_cell*)sockp;
|
|
const char *whatstr[]={ "none", "IN", "OUT", "INOUT", "REMOVE" };
|
|
|
|
LM_DBG("socket callback: s=%d e=%p what=%s\n", s, e, whatstr[what]);
|
|
if (what == CURL_POLL_REMOVE) {
|
|
/* if cell is NULL the handle has been removed by the event callback for timeout */
|
|
if (cell) {
|
|
if (cell->evset && cell->ev) {
|
|
LM_DBG("freeing event %p\n", cell->ev);
|
|
event_del(cell->ev);
|
|
event_free(cell->ev);
|
|
cell->ev=NULL;
|
|
cell->evset=0;
|
|
}
|
|
}
|
|
else {
|
|
LM_DBG("REMOVE action without cell, handler timed out.\n");
|
|
}
|
|
}
|
|
else {
|
|
if (!cell) {
|
|
LM_DBG("Adding data: %s\n", whatstr[what]);
|
|
addsock(s, e, what, g);
|
|
}
|
|
else {
|
|
LM_DBG("Changing action from %s to %s\n",
|
|
whatstr[cell->action], whatstr[what]);
|
|
setsock(cell, s, e, what);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
int check_mcode(CURLMcode code, char *error)
|
|
{
|
|
const char *s;
|
|
if ( CURLM_OK != code && CURLM_CALL_MULTI_PERFORM != code ) {
|
|
switch (code) {
|
|
case CURLM_BAD_HANDLE: s="CURLM_BAD_HANDLE"; break;
|
|
case CURLM_BAD_EASY_HANDLE: s="CURLM_BAD_EASY_HANDLE"; break;
|
|
case CURLM_OUT_OF_MEMORY: s="CURLM_OUT_OF_MEMORY"; break;
|
|
case CURLM_INTERNAL_ERROR: s="CURLM_INTERNAL_ERROR"; break;
|
|
case CURLM_UNKNOWN_OPTION: s="CURLM_UNKNOWN_OPTION"; break;
|
|
case CURLM_LAST: s="CURLM_LAST"; break;
|
|
case CURLM_BAD_SOCKET: s="CURLM_BAD_SOCKET"; break;
|
|
default: s="CURLM_unknown";
|
|
break;
|
|
}
|
|
LM_ERR("ERROR: %s\n", s);
|
|
strncpy(error, s, strlen(s)+1);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* CURLOPT_DEBUGFUNCTION */
|
|
int debug_cb(CURL *handle,
|
|
curl_infotype type,
|
|
char *data,
|
|
size_t size,
|
|
void *userptr)
|
|
{
|
|
char *prefix;
|
|
switch (type) {
|
|
case CURLINFO_TEXT:
|
|
prefix = "[cURL]";
|
|
break;
|
|
case CURLINFO_HEADER_IN:
|
|
prefix = "[cURL hdr in]";
|
|
break;
|
|
case CURLINFO_HEADER_OUT:
|
|
prefix = "[cURL hdr out]";
|
|
break;
|
|
case CURLINFO_DATA_IN:
|
|
case CURLINFO_DATA_OUT:
|
|
case CURLINFO_SSL_DATA_OUT:
|
|
case CURLINFO_SSL_DATA_IN:
|
|
default:
|
|
return 0;
|
|
break;
|
|
}
|
|
LM_INFO("%s %.*s"/* cURL includes final \n */, prefix, (int)size, data);
|
|
return 0;
|
|
}
|
|
/* CURLOPT_WRITEFUNCTION */
|
|
size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data)
|
|
{
|
|
size_t realsize = size * nmemb;
|
|
struct http_m_cell *cell;
|
|
CURL *easy = (CURL*) data;
|
|
int old_len;
|
|
|
|
LM_DBG("data received: %.*s [%d]\n", (int)realsize, (char*)ptr, (int)realsize);
|
|
|
|
cell = http_m_cell_lookup(easy);
|
|
if (cell == NULL) {
|
|
LM_ERR("Cell for handler %p not found in table\n", easy);
|
|
return -1;
|
|
}
|
|
|
|
if (cell->reply == NULL) {
|
|
cell->reply = (struct http_m_reply*)shm_malloc(sizeof(struct http_m_reply));
|
|
if (cell->reply == NULL) {
|
|
LM_ERR("Cannot allocate shm memory for reply\n");
|
|
return -1;
|
|
}
|
|
memset( cell->reply, 0, sizeof(struct http_m_reply) );
|
|
cell->reply->result = (str *)shm_malloc(sizeof(str));
|
|
if (cell->reply->result == NULL) {
|
|
LM_ERR("Cannot allocate shm memory for reply's result\n");
|
|
shm_free(cell->reply);
|
|
return -1;
|
|
}
|
|
memset( cell->reply->result, 0, sizeof(str) );
|
|
}
|
|
|
|
old_len = cell->reply->result->len;
|
|
cell->reply->result->len += realsize;
|
|
cell->reply->result->s = (char*)shm_realloc(cell->reply->result->s, cell->reply->result->len);
|
|
if (cell->reply->result->s == NULL) {
|
|
LM_ERR("Cannot allocate shm memory for reply's result\n");
|
|
shm_free(cell->reply->result);
|
|
shm_free(cell->reply);
|
|
cell->reply = NULL;
|
|
return -1;
|
|
}
|
|
strncpy(cell->reply->result->s + old_len, ptr, cell->reply->result->len - old_len);
|
|
|
|
if (cell->easy == NULL ) { /* TODO: when does this happen? */
|
|
LM_DBG("cell %p easy handler is null\n", cell);
|
|
}
|
|
else {
|
|
LM_DBG("getting easy handler info (%p)\n", cell->easy);
|
|
curl_easy_getinfo(cell->easy, CURLINFO_HTTP_CODE, &cell->reply->retcode);
|
|
}
|
|
|
|
return realsize;
|
|
}
|
|
|
|
void reply_error(struct http_m_cell *cell)
|
|
{
|
|
struct http_m_reply *reply;
|
|
LM_DBG("replying error for cell=%p\n", cell);
|
|
|
|
reply = (struct http_m_reply*)pkg_malloc(sizeof(struct http_m_reply));
|
|
if (reply == NULL) {
|
|
LM_ERR("Cannot allocate pkg memory for reply's result\n");
|
|
return;
|
|
}
|
|
memset( reply, 0, sizeof(struct http_m_reply) );
|
|
reply->result = NULL;
|
|
reply->retcode = 0;
|
|
|
|
if (cell) {
|
|
strncpy(reply->error, cell->error, strlen(cell->error));
|
|
reply->error[strlen(cell->error)] = '\0';
|
|
} else {
|
|
reply->error[0] = '\0';
|
|
}
|
|
|
|
cell->cb(reply, cell->param);
|
|
|
|
pkg_free(reply);
|
|
|
|
return;
|
|
}
|
|
|
|
static void *curl_shm_malloc(size_t size)
|
|
{
|
|
void *p = shm_malloc(size);
|
|
return p;
|
|
}
|
|
static void curl_shm_free(void *ptr)
|
|
{
|
|
if (ptr)
|
|
shm_free(ptr);
|
|
}
|
|
|
|
static void *curl_shm_realloc(void *ptr, size_t size)
|
|
{
|
|
void *p = shm_realloc(ptr, size);
|
|
|
|
return p;
|
|
}
|
|
|
|
static void *curl_shm_calloc(size_t nmemb, size_t size)
|
|
{
|
|
void *p = shm_malloc(nmemb * size);
|
|
if (p)
|
|
memset(p, '\0', nmemb * size);
|
|
|
|
return p;
|
|
}
|
|
|
|
static char *curl_shm_strdup(const char *cp)
|
|
{
|
|
char *rval;
|
|
int len;
|
|
|
|
len = strlen(cp) + 1;
|
|
rval = shm_malloc(len);
|
|
if (!rval)
|
|
return NULL;
|
|
|
|
memcpy(rval, cp, len);
|
|
return rval;
|
|
}
|
|
|
|
void set_curl_mem_callbacks(void)
|
|
{
|
|
CURLcode rc;
|
|
|
|
switch (curl_memory_manager) {
|
|
case 0:
|
|
LM_DBG("Setting shm memory callbacks for cURL\n");
|
|
rc = curl_global_init_mem(CURL_GLOBAL_ALL,
|
|
curl_shm_malloc,
|
|
curl_shm_free,
|
|
curl_shm_realloc,
|
|
curl_shm_strdup,
|
|
curl_shm_calloc);
|
|
if (rc != 0) {
|
|
LM_ERR("Cannot set memory callbacks for cURL: %d\n", rc);
|
|
}
|
|
break;
|
|
case 1:
|
|
LM_DBG("Initilizing cURL with sys malloc\n");
|
|
rc = curl_global_init(CURL_GLOBAL_ALL);
|
|
if (rc != 0) {
|
|
LM_ERR("Cannot initialize cURL: %d\n", rc);
|
|
}
|
|
break;
|
|
default:
|
|
LM_ERR ("invalid memory manager: %d\n", curl_memory_manager);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
int init_http_multi(struct event_base *evbase, struct http_m_global *wg)
|
|
{
|
|
g = wg;
|
|
g->evbase = evbase;
|
|
|
|
set_curl_mem_callbacks();
|
|
|
|
g->multi = curl_multi_init();
|
|
LM_DBG("curl_multi %p initialized on global %p (evbase %p)\n", g->multi, g, evbase);
|
|
|
|
g->timer_event = evtimer_new(g->evbase, timer_cb, g);
|
|
|
|
/* setup the generic multi interface options we want */
|
|
curl_multi_setopt(g->multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
|
|
curl_multi_setopt(g->multi, CURLMOPT_SOCKETDATA, g);
|
|
curl_multi_setopt(g->multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb);
|
|
curl_multi_setopt(g->multi, CURLMOPT_TIMERDATA, g);
|
|
|
|
return init_http_m_table(hash_size);
|
|
}
|
|
|
|
int new_request(str *query, str *post, http_m_params_t *query_params, http_multi_cbe_t cb, void *param)
|
|
{
|
|
|
|
LM_DBG("received query %.*s with timeout %d, tls_verify_peer %d, tls_verify_host %d (param=%p)\n",
|
|
query->len, query->s, query_params->timeout, query_params->tls_verify_peer, query_params->tls_verify_host, param);
|
|
|
|
CURL *easy;
|
|
CURLMcode rc;
|
|
|
|
struct http_m_cell *cell;
|
|
|
|
update_stat(requests, 1);
|
|
|
|
easy = NULL;
|
|
cell = NULL;
|
|
|
|
easy = curl_easy_init();
|
|
if (!easy) {
|
|
LM_ERR("curl_easy_init() failed!\n");
|
|
update_stat(errors, 1);
|
|
return -1;
|
|
}
|
|
|
|
cell = build_http_m_cell(easy);
|
|
if (!cell) {
|
|
LM_ERR("cannot create cell!\n");
|
|
update_stat(errors, 1);
|
|
LM_DBG("cleaning up curl handler %p\n", easy);
|
|
curl_easy_cleanup(easy);
|
|
return -1;
|
|
}
|
|
|
|
link_http_m_cell(cell);
|
|
|
|
cell->global = g;
|
|
cell->easy=easy;
|
|
cell->error[0] = '\0';
|
|
cell->params = *query_params;
|
|
cell->param = param;
|
|
cell->cb = cb;
|
|
cell->url = (char*)shm_malloc(query->len + 1);
|
|
if (cell->url==0) {
|
|
LM_ERR("no more shm mem\n");
|
|
goto error;
|
|
}
|
|
strncpy(cell->url, query->s, query->len);
|
|
cell->url[query->len] = '\0';
|
|
|
|
curl_easy_setopt(cell->easy, CURLOPT_URL, cell->url);
|
|
curl_easy_setopt(cell->easy, CURLOPT_WRITEFUNCTION, write_cb);
|
|
curl_easy_setopt(cell->easy, CURLOPT_WRITEDATA, easy);
|
|
if (curl_verbose) {
|
|
curl_easy_setopt(cell->easy, CURLOPT_VERBOSE, 1L);
|
|
curl_easy_setopt(cell->easy, CURLOPT_DEBUGFUNCTION, debug_cb);
|
|
}
|
|
curl_easy_setopt(cell->easy, CURLOPT_ERRORBUFFER, cell->error);
|
|
curl_easy_setopt(cell->easy, CURLOPT_PRIVATE, cell);
|
|
curl_easy_setopt(cell->easy, CURLOPT_SSL_VERIFYPEER, cell->params.tls_verify_peer);
|
|
curl_easy_setopt(cell->easy, CURLOPT_SSL_VERIFYHOST, cell->params.tls_verify_host?2:0);
|
|
curl_easy_setopt(cell->easy, CURLOPT_SSLVERSION, tls_version);
|
|
|
|
if (cell->params.tls_client_cert.s && cell->params.tls_client_cert.len > 0) {
|
|
curl_easy_setopt(cell->easy, CURLOPT_SSLCERT, cell->params.tls_client_cert.s);
|
|
}
|
|
|
|
if (cell->params.tls_client_key.s && cell->params.tls_client_key.len > 0) {
|
|
curl_easy_setopt(cell->easy, CURLOPT_SSLKEY, cell->params.tls_client_key.s);
|
|
}
|
|
|
|
if (cell->params.tls_ca_path.s && cell->params.tls_ca_path.len > 0) {
|
|
curl_easy_setopt(cell->easy, CURLOPT_CAPATH, cell->params.tls_ca_path.s);
|
|
}
|
|
|
|
curl_easy_setopt(cell->easy, CURLOPT_HEADER, 1);
|
|
if (cell->params.headers) {
|
|
curl_easy_setopt(cell->easy, CURLOPT_HTTPHEADER, cell->params.headers);
|
|
}
|
|
|
|
if (post && post->s && post->len) {
|
|
curl_easy_setopt(cell->easy, CURLOPT_POST, 1L);
|
|
cell->post_data = shm_malloc(post->len + 1);
|
|
if (cell->post_data == NULL) {
|
|
LM_ERR("cannot allocate pkg memory for post\n");
|
|
goto error;
|
|
}
|
|
strncpy(cell->post_data, post->s, post->len);
|
|
cell->post_data[post->len] = '\0';
|
|
curl_easy_setopt(cell->easy, CURLOPT_POSTFIELDS, cell->post_data);
|
|
}
|
|
|
|
switch (cell->params.method) {
|
|
case 1:
|
|
curl_easy_setopt(cell->easy, CURLOPT_CUSTOMREQUEST, "GET");
|
|
break;
|
|
case 2:
|
|
curl_easy_setopt(cell->easy, CURLOPT_CUSTOMREQUEST, "POST");
|
|
break;
|
|
case 3:
|
|
curl_easy_setopt(cell->easy, CURLOPT_CUSTOMREQUEST, "PUT");
|
|
break;
|
|
case 4:
|
|
curl_easy_setopt(cell->easy, CURLOPT_CUSTOMREQUEST, "DELETE");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
LM_DBG("Adding easy %p to multi %p (%.*s)\n", cell->easy, g->multi, query->len, query->s);
|
|
rc = curl_multi_add_handle(g->multi, cell->easy);
|
|
if (check_mcode(rc, cell->error) < 0) {
|
|
LM_ERR("error adding curl handler: %s\n", cell->error);
|
|
goto error;
|
|
}
|
|
/* note that the add_handle() will set a time-out to trigger very soon so
|
|
* that the necessary socket_action() call will be called by this app */
|
|
return 0;
|
|
|
|
error:
|
|
update_stat(errors, 1);
|
|
if (easy) {
|
|
LM_DBG("cleaning up curl handler %p\n", easy);
|
|
curl_easy_cleanup(easy);
|
|
}
|
|
free_http_m_cell(cell);
|
|
return -1;
|
|
}
|
|
|
|
/* Check for completed transfers, and remove their easy handles */
|
|
void check_multi_info(struct http_m_global *g)
|
|
{
|
|
char *eff_url;
|
|
CURLMsg *msg;
|
|
int msgs_left;
|
|
CURL *easy;
|
|
CURLcode res;
|
|
|
|
struct http_m_cell *cell;
|
|
|
|
LM_DBG("REMAINING: %d\n", g->still_running);
|
|
while ((msg = curl_multi_info_read(g->multi, &msgs_left))) {
|
|
if (msg->msg == CURLMSG_DONE) {
|
|
easy = msg->easy_handle;
|
|
res = msg->data.result;
|
|
curl_easy_getinfo(easy, CURLINFO_PRIVATE, &cell);
|
|
curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url);
|
|
LM_DBG("DONE: %s => (%d) %s\n", eff_url, res, cell->error);
|
|
|
|
cell = http_m_cell_lookup(easy);
|
|
if (msg->data.result != 0) {
|
|
LM_ERR("handle %p returned error %d: %s\n", easy, res, cell->error);
|
|
update_stat(errors, 1);
|
|
reply_error(cell);
|
|
} else {
|
|
cell->reply->error[0] = '\0';
|
|
cell->cb(cell->reply, cell->param);
|
|
|
|
LM_DBG("reply: [%d] %.*s [%d]\n", (int)cell->reply->retcode, cell->reply->result->len, cell->reply->result->s, cell->reply->result->len);
|
|
update_stat(replies, 1);
|
|
}
|
|
|
|
if (cell != 0) {
|
|
LM_DBG("cleaning up cell %p\n", cell);
|
|
unlink_http_m_cell(cell);
|
|
free_http_m_cell(cell);
|
|
}
|
|
|
|
LM_DBG("Removing handle %p\n", easy);
|
|
curl_multi_remove_handle(g->multi, easy);
|
|
curl_easy_cleanup(easy);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* set cell's socket information and assign an event to the socket */
|
|
void setsock(struct http_m_cell *cell, curl_socket_t s, CURL*e, int act)
|
|
{
|
|
|
|
struct timeval timeout;
|
|
|
|
int kind =
|
|
(act&CURL_POLL_IN?EV_READ:0)|(act&CURL_POLL_OUT?EV_WRITE:0)|EV_PERSIST;
|
|
struct http_m_global *g = cell->global;
|
|
cell->sockfd = s;
|
|
cell->action = act;
|
|
cell->easy = e;
|
|
if (cell->evset && cell->ev) {
|
|
event_del(cell->ev);
|
|
event_free(cell->ev);
|
|
cell->ev=NULL;
|
|
cell->evset=0;
|
|
}
|
|
cell->ev = event_new(g->evbase, cell->sockfd, kind, event_cb, e);
|
|
LM_DBG("added event %p to socket %d\n", cell->ev, cell->sockfd);
|
|
cell->evset = 1;
|
|
|
|
|
|
timeout.tv_sec = cell->params.timeout/1000;
|
|
timeout.tv_usec = (cell->params.timeout%1000)*1000;
|
|
|
|
event_add(cell->ev, &timeout);
|
|
}
|
|
|
|
|
|
|
|
/* assign a socket to the multi handler */
|
|
void addsock(curl_socket_t s, CURL *easy, int action, struct http_m_global *g)
|
|
{
|
|
struct http_m_cell *cell;
|
|
|
|
cell = http_m_cell_lookup(easy);
|
|
if (!cell)
|
|
return;
|
|
setsock(cell, s, cell->easy, action);
|
|
curl_multi_assign(g->multi, s, cell);
|
|
}
|
|
|