Curl - Load a URL. More...
#include "asterisk.h"
#include <curl/curl.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/cli.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/threadstorage.h"
Go to the source code of this file.
Data Structures | |
struct | curl_settings |
struct | global_curl_info |
Defines | |
#define | CURLOPT_SPECIAL_HASHCOMPAT -500 |
#define | CURLVERSION_ATLEAST(a, b, c) ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c)))) |
Enumerations | |
enum | optiontype { OT_BOOLEAN, OT_INTEGER, OT_INTEGER_MS, OT_STRING, OT_ENUM } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | acf_curl_exec (struct ast_channel *chan, const char *cmd, char *info, char *buf, size_t len) |
static int | acf_curlopt_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | acf_curlopt_write (struct ast_channel *chan, const char *cmd, char *name, const char *value) |
AST_THREADSTORAGE_CUSTOM_SCOPE (curl_instance, curl_instance_init, curl_instance_cleanup, static) | |
static void | curl_instance_cleanup (void *data) |
static int | curl_instance_init (void *data) |
static void | curlds_free (void *data) |
static int | load_module (void) |
static int | parse_curlopt_key (const char *name, CURLoption *key, enum optiontype *ot) |
static int | unload_module (void) |
static size_t | WriteMemoryCallback (void *ptr, size_t size, size_t nmemb, void *data) |
Variables | |
static struct ast_module_info __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Load external URL" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } |
struct ast_custom_function | acf_curl |
struct ast_custom_function | acf_curlopt |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_datastore_info | curl_info |
struct global_curl_info | global_curl_info |
static const char * | global_useragent = "asterisk-libcurl-agent/1.0" |
Curl - Load a URL.
Definition in file func_curl.c.
#define CURLOPT_SPECIAL_HASHCOMPAT -500 |
Definition at line 56 of file func_curl.c.
Referenced by acf_curl_exec(), and parse_curlopt_key().
#define CURLVERSION_ATLEAST | ( | a, | |
b, | |||
c | |||
) | ((LIBCURL_VERSION_MAJOR > (a)) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR > (b))) || ((LIBCURL_VERSION_MAJOR == (a)) && (LIBCURL_VERSION_MINOR == (b)) && (LIBCURL_VERSION_PATCH >= (c)))) |
Definition at line 53 of file func_curl.c.
enum optiontype |
Definition at line 86 of file func_curl.c.
{ OT_BOOLEAN, OT_INTEGER, OT_INTEGER_MS, OT_STRING, OT_ENUM, };
static void __reg_module | ( | void | ) | [static] |
Definition at line 572 of file func_curl.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 572 of file func_curl.c.
static int acf_curl_exec | ( | struct ast_channel * | chan, |
const char * | cmd, | ||
char * | info, | ||
char * | buf, | ||
size_t | len | ||
) | [static] |
Definition at line 397 of file func_curl.c.
References AST_APP_ARG, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_datastore_find(), ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_free, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_STANDARD_APP_ARGS, ast_str_append(), ast_str_buffer(), ast_str_create(), ast_str_strlen(), ast_str_trim_blanks(), ast_strlen_zero(), ast_threadstorage_get(), ast_uri_decode(), CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, curl_settings::key, curl_settings::list, LOG_ERROR, LOG_WARNING, name, pbx_builtin_setvar_helper(), str, strsep(), url, and curl_settings::value.
{ struct ast_str *str = ast_str_create(16); int ret = -1; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(url); AST_APP_ARG(postdata); ); CURL **curl; struct curl_settings *cur; struct ast_datastore *store = NULL; int hashcompat = 0; AST_LIST_HEAD(global_curl_info, curl_settings) *list = NULL; *buf = '\0'; if (ast_strlen_zero(info)) { ast_log(LOG_WARNING, "CURL requires an argument (URL)\n"); ast_free(str); return -1; } AST_STANDARD_APP_ARGS(args, info); if (chan) { ast_autoservice_start(chan); } if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) { ast_log(LOG_ERROR, "Cannot allocate curl structure\n"); return -1; } AST_LIST_LOCK(&global_curl_info); AST_LIST_TRAVERSE(&global_curl_info, cur, list) { if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) { hashcompat = (cur->value != NULL) ? 1 : 0; } else { curl_easy_setopt(*curl, cur->key, cur->value); } } if (chan && (store = ast_channel_datastore_find(chan, &curl_info, NULL))) { list = store->data; AST_LIST_LOCK(list); AST_LIST_TRAVERSE(list, cur, list) { if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) { hashcompat = (cur->value != NULL) ? 1 : 0; } else { curl_easy_setopt(*curl, cur->key, cur->value); } } } curl_easy_setopt(*curl, CURLOPT_URL, args.url); curl_easy_setopt(*curl, CURLOPT_FILE, (void *) &str); if (args.postdata) { curl_easy_setopt(*curl, CURLOPT_POST, 1); curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args.postdata); } curl_easy_perform(*curl); if (store) { AST_LIST_UNLOCK(list); } AST_LIST_UNLOCK(&global_curl_info); if (args.postdata) { curl_easy_setopt(*curl, CURLOPT_POST, 0); } if (ast_str_strlen(str)) { ast_str_trim_blanks(str); ast_debug(3, "str='%s'\n", ast_str_buffer(str)); if (hashcompat) { char *remainder = ast_str_buffer(str); char *piece; struct ast_str *fields = ast_str_create(ast_str_strlen(str) / 2); struct ast_str *values = ast_str_create(ast_str_strlen(str) / 2); int rowcount = 0; while (fields && values && (piece = strsep(&remainder, "&"))) { char *name = strsep(&piece, "="); if (!piece) { piece = ""; } ast_uri_decode(piece); ast_uri_decode(name); ast_str_append(&fields, 0, "%s%s", rowcount ? "," : "", name); ast_str_append(&values, 0, "%s%s", rowcount ? "," : "", piece); rowcount++; } pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields)); ast_copy_string(buf, ast_str_buffer(values), len); ast_free(fields); ast_free(values); } else { ast_copy_string(buf, ast_str_buffer(str), len); } ret = 0; } ast_free(str); if (chan) ast_autoservice_stop(chan); return ret; }
static int acf_curlopt_read | ( | struct ast_channel * | chan, |
const char * | cmd, | ||
char * | data, | ||
char * | buf, | ||
size_t | len | ||
) | [static] |
Definition at line 282 of file func_curl.c.
References ast_channel_datastore_find(), ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, global_curl_info, curl_settings::key, curl_settings::list, LOG_ERROR, OT_BOOLEAN, OT_INTEGER, OT_INTEGER_MS, OT_STRING, parse_curlopt_key(), and curl_settings::value.
{ struct ast_datastore *store; struct global_curl_info *list[2] = { &global_curl_info, NULL }; struct curl_settings *cur = NULL; CURLoption key; enum optiontype ot; int i; if (parse_curlopt_key(data, &key, &ot)) { ast_log(LOG_ERROR, "Unrecognized option: '%s'\n", data); return -1; } if (chan && (store = ast_channel_datastore_find(chan, &curl_info, NULL))) { list[0] = store->data; list[1] = &global_curl_info; } for (i = 0; i < 2; i++) { if (!list[i]) { break; } AST_LIST_LOCK(list[i]); AST_LIST_TRAVERSE(list[i], cur, list) { if (cur->key == key) { if (ot == OT_BOOLEAN || ot == OT_INTEGER) { snprintf(buf, len, "%ld", (long)cur->value); } else if (ot == OT_INTEGER_MS) { if ((long)cur->value % 1000 == 0) { snprintf(buf, len, "%ld", (long)cur->value / 1000); } else { snprintf(buf, len, "%.3f", (double)((long)cur->value) / 1000.0); } } else if (ot == OT_STRING) { ast_debug(1, "Found entry %p, with key %d and value %p\n", cur, cur->key, cur->value); ast_copy_string(buf, cur->value, len); } else if (key == CURLOPT_PROXYTYPE) { if (0) { #if CURLVERSION_ATLEAST(7,15,2) } else if ((long)cur->value == CURLPROXY_SOCKS4) { ast_copy_string(buf, "socks4", len); #endif #if CURLVERSION_ATLEAST(7,18,0) } else if ((long)cur->value == CURLPROXY_SOCKS4A) { ast_copy_string(buf, "socks4a", len); #endif } else if ((long)cur->value == CURLPROXY_SOCKS5) { ast_copy_string(buf, "socks5", len); #if CURLVERSION_ATLEAST(7,18,0) } else if ((long)cur->value == CURLPROXY_SOCKS5_HOSTNAME) { ast_copy_string(buf, "socks5hostname", len); #endif #if CURLVERSION_ATLEAST(7,10,0) } else if ((long)cur->value == CURLPROXY_HTTP) { ast_copy_string(buf, "http", len); #endif } else { ast_copy_string(buf, "unknown", len); } } break; } } AST_LIST_UNLOCK(list[i]); if (cur) { break; } } return cur ? 0 : -1; }
static int acf_curlopt_write | ( | struct ast_channel * | chan, |
const char * | cmd, | ||
char * | name, | ||
const char * | value | ||
) | [static] |
Definition at line 163 of file func_curl.c.
References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_datastore_alloc(), ast_datastore_free(), ast_debug, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_true(), ast_datastore::data, free, global_curl_info, curl_settings::key, curl_settings::list, LOG_ERROR, OT_BOOLEAN, OT_ENUM, OT_INTEGER, OT_INTEGER_MS, OT_STRING, and parse_curlopt_key().
{ struct ast_datastore *store; struct global_curl_info *list; struct curl_settings *cur, *new = NULL; CURLoption key; enum optiontype ot; if (chan) { if (!(store = ast_channel_datastore_find(chan, &curl_info, NULL))) { /* Create a new datastore */ if (!(store = ast_datastore_alloc(&curl_info, NULL))) { ast_log(LOG_ERROR, "Unable to allocate new datastore. Cannot set any CURL options\n"); return -1; } if (!(list = ast_calloc(1, sizeof(*list)))) { ast_log(LOG_ERROR, "Unable to allocate list head. Cannot set any CURL options\n"); ast_datastore_free(store); } store->data = list; AST_LIST_HEAD_INIT(list); ast_channel_datastore_add(chan, store); } else { list = store->data; } } else { /* Populate the global structure */ list = &global_curl_info; } if (!parse_curlopt_key(name, &key, &ot)) { if (ot == OT_BOOLEAN) { if ((new = ast_calloc(1, sizeof(*new)))) { new->value = (void *)((long) ast_true(value)); } } else if (ot == OT_INTEGER) { long tmp = atol(value); if ((new = ast_calloc(1, sizeof(*new)))) { new->value = (void *)tmp; } } else if (ot == OT_INTEGER_MS) { long tmp = atof(value) * 1000.0; if ((new = ast_calloc(1, sizeof(*new)))) { new->value = (void *)tmp; } } else if (ot == OT_STRING) { if ((new = ast_calloc(1, sizeof(*new) + strlen(value) + 1))) { new->value = (char *)new + sizeof(*new); strcpy(new->value, value); } } else if (ot == OT_ENUM) { if (key == CURLOPT_PROXYTYPE) { long ptype = #if CURLVERSION_ATLEAST(7,10,0) CURLPROXY_HTTP; #else CURLPROXY_SOCKS5; #endif if (0) { #if CURLVERSION_ATLEAST(7,15,2) } else if (!strcasecmp(value, "socks4")) { ptype = CURLPROXY_SOCKS4; #endif #if CURLVERSION_ATLEAST(7,18,0) } else if (!strcasecmp(value, "socks4a")) { ptype = CURLPROXY_SOCKS4A; #endif #if CURLVERSION_ATLEAST(7,18,0) } else if (!strcasecmp(value, "socks5")) { ptype = CURLPROXY_SOCKS5; #endif #if CURLVERSION_ATLEAST(7,18,0) } else if (!strncasecmp(value, "socks5", 6)) { ptype = CURLPROXY_SOCKS5_HOSTNAME; #endif } if ((new = ast_calloc(1, sizeof(*new)))) { new->value = (void *)ptype; } } else { /* Highly unlikely */ goto yuck; } } /* Memory allocation error */ if (!new) { return -1; } new->key = key; } else { yuck: ast_log(LOG_ERROR, "Unrecognized option: %s\n", name); return -1; } /* Remove any existing entry */ AST_LIST_LOCK(list); AST_LIST_TRAVERSE_SAFE_BEGIN(list, cur, list) { if (cur->key == new->key) { AST_LIST_REMOVE_CURRENT(list); free(cur); break; } } AST_LIST_TRAVERSE_SAFE_END /* Insert new entry */ ast_debug(1, "Inserting entry %p with key %d and value %p\n", new, new->key, new->value); AST_LIST_INSERT_TAIL(list, new, list); AST_LIST_UNLOCK(list); return 0; }
AST_THREADSTORAGE_CUSTOM_SCOPE | ( | curl_instance | , |
curl_instance_init | , | ||
curl_instance_cleanup | , | ||
static | |||
) |
static void curl_instance_cleanup | ( | void * | data | ) | [static] |
Definition at line 386 of file func_curl.c.
References ast_free.
{ CURL **curl = data; curl_easy_cleanup(*curl); ast_free(data); }
static int curl_instance_init | ( | void * | data | ) | [static] |
Definition at line 371 of file func_curl.c.
References global_useragent, and WriteMemoryCallback().
{ CURL **curl = data; if (!(*curl = curl_easy_init())) return -1; curl_easy_setopt(*curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(*curl, CURLOPT_TIMEOUT, 180); curl_easy_setopt(*curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(*curl, CURLOPT_USERAGENT, global_useragent); return 0; }
static void curlds_free | ( | void * | data | ) | [static] |
Definition at line 73 of file func_curl.c.
References AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_REMOVE_HEAD, and free.
{ AST_LIST_HEAD(global_curl_info, curl_settings) *list = data; struct curl_settings *setting; if (!list) { return; } while ((setting = AST_LIST_REMOVE_HEAD(list, list))) { free(setting); } AST_LIST_HEAD_DESTROY(list); }
static int load_module | ( | void | ) | [static] |
Definition at line 555 of file func_curl.c.
References acf_curl, acf_curlopt, ast_custom_function_register, ast_load_resource(), ast_log(), ast_module_check(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, and LOG_ERROR.
{ int res; if (!ast_module_check("res_curl.so")) { if (ast_load_resource("res_curl.so") != AST_MODULE_LOAD_SUCCESS) { ast_log(LOG_ERROR, "Cannot load res_curl, so func_curl cannot be loaded\n"); return AST_MODULE_LOAD_DECLINE; } } res = ast_custom_function_register(&acf_curl); res |= ast_custom_function_register(&acf_curlopt); return res; }
static int parse_curlopt_key | ( | const char * | name, |
CURLoption * | key, | ||
enum optiontype * | ot | ||
) | [static] |
Definition at line 94 of file func_curl.c.
References CURLOPT_SPECIAL_HASHCOMPAT, OT_BOOLEAN, OT_ENUM, OT_INTEGER, OT_INTEGER_MS, and OT_STRING.
Referenced by acf_curlopt_read(), and acf_curlopt_write().
{ if (!strcasecmp(name, "header")) { *key = CURLOPT_HEADER; *ot = OT_BOOLEAN; } else if (!strcasecmp(name, "proxy")) { *key = CURLOPT_PROXY; *ot = OT_STRING; } else if (!strcasecmp(name, "proxyport")) { *key = CURLOPT_PROXYPORT; *ot = OT_INTEGER; } else if (!strcasecmp(name, "proxytype")) { *key = CURLOPT_PROXYTYPE; *ot = OT_ENUM; } else if (!strcasecmp(name, "dnstimeout")) { *key = CURLOPT_DNS_CACHE_TIMEOUT; *ot = OT_INTEGER; } else if (!strcasecmp(name, "userpwd")) { *key = CURLOPT_USERPWD; *ot = OT_STRING; } else if (!strcasecmp(name, "proxyuserpwd")) { *key = CURLOPT_PROXYUSERPWD; *ot = OT_STRING; } else if (!strcasecmp(name, "maxredirs")) { *key = CURLOPT_MAXREDIRS; *ot = OT_INTEGER; } else if (!strcasecmp(name, "referer")) { *key = CURLOPT_REFERER; *ot = OT_STRING; } else if (!strcasecmp(name, "useragent")) { *key = CURLOPT_USERAGENT; *ot = OT_STRING; } else if (!strcasecmp(name, "cookie")) { *key = CURLOPT_COOKIE; *ot = OT_STRING; } else if (!strcasecmp(name, "ftptimeout")) { *key = CURLOPT_FTP_RESPONSE_TIMEOUT; *ot = OT_INTEGER; } else if (!strcasecmp(name, "httptimeout")) { #if CURLVERSION_ATLEAST(7,16,2) *key = CURLOPT_TIMEOUT_MS; *ot = OT_INTEGER_MS; #else *key = CURLOPT_TIMEOUT; *ot = OT_INTEGER; #endif } else if (!strcasecmp(name, "conntimeout")) { #if CURLVERSION_ATLEAST(7,16,2) *key = CURLOPT_CONNECTTIMEOUT_MS; *ot = OT_INTEGER_MS; #else *key = CURLOPT_CONNECTTIMEOUT; *ot = OT_INTEGER; #endif } else if (!strcasecmp(name, "ftptext")) { *key = CURLOPT_TRANSFERTEXT; *ot = OT_BOOLEAN; } else if (!strcasecmp(name, "ssl_verifypeer")) { *key = CURLOPT_SSL_VERIFYPEER; *ot = OT_BOOLEAN; } else if (!strcasecmp(name, "hashcompat")) { *key = CURLOPT_SPECIAL_HASHCOMPAT; *ot = OT_BOOLEAN; } else { return -1; } return 0; }
static int unload_module | ( | void | ) | [static] |
Definition at line 545 of file func_curl.c.
References acf_curl, acf_curlopt, and ast_custom_function_unregister().
{ int res; res = ast_custom_function_unregister(&acf_curl); res |= ast_custom_function_unregister(&acf_curlopt); return res; }
static size_t WriteMemoryCallback | ( | void * | ptr, |
size_t | size, | ||
size_t | nmemb, | ||
void * | data | ||
) | [static] |
Definition at line 355 of file func_curl.c.
References ast_debug, ast_str_append_substr(), ast_str_size(), and ast_str_strlen().
Referenced by curl_instance_init().
{ register int realsize = size * nmemb; struct ast_str **pstr = (struct ast_str **)data; ast_debug(3, "Called with data=%p, str=%p, realsize=%d, len=%zu, used=%zu\n", data, *pstr, realsize, ast_str_size(*pstr), ast_str_strlen(*pstr)); ast_str_append_substr(pstr, 0, ptr, realsize); ast_debug(3, "Now, len=%zu, used=%zu\n", ast_str_size(*pstr), ast_str_strlen(*pstr)); return realsize; }
struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Load external URL" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static] |
Definition at line 572 of file func_curl.c.
struct ast_custom_function acf_curl |
Definition at line 508 of file func_curl.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function acf_curlopt |
Definition at line 518 of file func_curl.c.
Referenced by load_module(), and unload_module().
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 572 of file func_curl.c.
struct ast_datastore_info curl_info [static] |
{ .type = "CURL", .destroy = curlds_free, }
Definition at line 60 of file func_curl.c.
struct global_curl_info global_curl_info |
Referenced by acf_curlopt_read(), and acf_curlopt_write().
const char* global_useragent = "asterisk-libcurl-agent/1.0" [static] |
Definition at line 369 of file func_curl.c.
Referenced by curl_instance_init().