Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
Data Structures | Macros | Enumerations | Functions | Variables
func_curl.c File Reference

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"
#include "asterisk/test.h"
Include dependency graph for func_curl.c:

Go to the source code of this file.

Data Structures

struct  curl_args
 
struct  curl_settings
 
struct  curl_write_callback_data
 Callback data passed to WriteMemoryCallback. More...
 
struct  global_curl_info
 

Macros

#define CURLOPT_SPECIAL_FAILURE_CODE   999
 
#define CURLOPT_SPECIAL_HASHCOMPAT   ((CURLoption) -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  hashcompat { HASHCOMPAT_NO = 0 , HASHCOMPAT_YES , HASHCOMPAT_LEGACY }
 
enum  optiontype {
  OT_BOOLEAN , OT_INTEGER , OT_INTEGER_MS , OT_STRING ,
  OT_ENUM
}
 

Functions

static void __init_curl_instance (void)
 
static void __init_thread_escapebuf (void)
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
static int acf_curl_exec (struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len)
 
static int acf_curl_helper (struct ast_channel *chan, struct curl_args *args)
 
static int acf_curl_write (struct ast_channel *chan, const char *cmd, char *name, const char *value)
 
static int acf_curlopt_helper (struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, ssize_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_read2 (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
 
static int acf_curlopt_write (struct ast_channel *chan, const char *cmd, char *name, const char *value)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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 int url_is_vulnerable (const char *url)
 Check for potential HTTP injection risk. More...
 
static size_t WriteMemoryCallback (void *ptr, size_t size, size_t nmemb, void *data)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Load external URL" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DEPEND2, .requires = "res_curl", }
 
static struct ast_custom_function acf_curl
 
static struct ast_custom_function acf_curlopt
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static const struct ast_datastore_info curl_info
 
static struct ast_threadstorage curl_instance = { .once = PTHREAD_ONCE_INIT , .key_init = __init_curl_instance , .custom_init = curl_instance_init , }
 
struct global_curl_info global_curl_info = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }
 
static struct ast_threadstorage thread_escapebuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_thread_escapebuf , .custom_init = NULL , }
 

Detailed Description

Curl - Load a URL.

Author
Tilghman Lesher curl-.nosp@m.2005.nosp@m.0919@.nosp@m.the-.nosp@m.tilgh.nosp@m.man..nosp@m.com
Note
Brian Wilkins bwilk.nosp@m.ins@.nosp@m.cfl.r.nosp@m.r.co.nosp@m.m (Added POST option)
ExtRef:
Depends on the CURL library - http://curl.haxx.se/

Definition in file func_curl.c.

Macro Definition Documentation

◆ CURLOPT_SPECIAL_FAILURE_CODE

#define CURLOPT_SPECIAL_FAILURE_CODE   999

Definition at line 252 of file func_curl.c.

◆ CURLOPT_SPECIAL_HASHCOMPAT

#define CURLOPT_SPECIAL_HASHCOMPAT   ((CURLoption) -500)

Definition at line 250 of file func_curl.c.

◆ CURLVERSION_ATLEAST

#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 247 of file func_curl.c.

Enumeration Type Documentation

◆ hashcompat

enum hashcompat
Enumerator
HASHCOMPAT_NO 
HASHCOMPAT_YES 
HASHCOMPAT_LEGACY 

Definition at line 291 of file func_curl.c.

291 {
292 HASHCOMPAT_NO = 0,
295};
@ HASHCOMPAT_NO
Definition: func_curl.c:292
@ HASHCOMPAT_LEGACY
Definition: func_curl.c:294
@ HASHCOMPAT_YES
Definition: func_curl.c:293

◆ optiontype

enum optiontype
Enumerator
OT_BOOLEAN 
OT_INTEGER 
OT_INTEGER_MS 
OT_STRING 
OT_ENUM 

Definition at line 283 of file func_curl.c.

283 {
287 OT_STRING,
288 OT_ENUM,
289};
@ OT_BOOLEAN
Definition: func_curl.c:284
@ OT_ENUM
Definition: func_curl.c:288
@ OT_STRING
Definition: func_curl.c:287
@ OT_INTEGER
Definition: func_curl.c:285
@ OT_INTEGER_MS
Definition: func_curl.c:286

Function Documentation

◆ __init_curl_instance()

static void __init_curl_instance ( void  )
static

Definition at line 703 of file func_curl.c.

723{

◆ __init_thread_escapebuf()

static void __init_thread_escapebuf ( void  )
static

Definition at line 704 of file func_curl.c.

723{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1060 of file func_curl.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1060 of file func_curl.c.

◆ acf_curl_exec()

static int acf_curl_exec ( struct ast_channel chan,
const char *  cmd,
char *  info,
struct ast_str **  buf,
ssize_t  len 
)
static

Definition at line 898 of file func_curl.c.

899{
900 struct curl_args curl_params = { 0, };
901 int res;
902
906 );
907
909
910 if (ast_strlen_zero(info)) {
911 ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
912 return -1;
913 }
914
915 curl_params.url = args.url;
916 curl_params.postdata = args.postdata;
917 curl_params.cb_data.str = ast_str_create(16);
918 if (!curl_params.cb_data.str) {
919 return -1;
920 }
921
922 res = acf_curl_helper(chan, &curl_params);
923 ast_str_set(buf, len, "%s", ast_str_buffer(curl_params.cb_data.str));
924 ast_free(curl_params.cb_data.str);
925
926 return res;
927}
#define ast_free(a)
Definition: astmm.h:180
#define ast_log
Definition: astobj2.c:42
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int acf_curl_helper(struct ast_channel *chan, struct curl_args *args)
Definition: func_curl.c:737
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define LOG_WARNING
def info(msg)
static char url[512]
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
const char * postdata
Definition: func_curl.c:733
struct curl_write_callback_data cb_data
Definition: func_curl.c:734
const char * url
Definition: func_curl.c:732
struct ast_str * str
If a string is being built, the string buffer.
Definition: func_curl.c:657
const char * args

References acf_curl_helper(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_free, ast_log, AST_STANDARD_APP_ARGS, ast_str_buffer(), ast_str_create, ast_str_set(), ast_strlen_zero(), buf, curl_args::cb_data, sip_to_pjsip::info(), len(), LOG_WARNING, curl_args::postdata, curl_write_callback_data::str, curl_args::url, and url.

◆ acf_curl_helper()

static int acf_curl_helper ( struct ast_channel chan,
struct curl_args args 
)
static

Definition at line 737 of file func_curl.c.

738{
739 struct ast_str *escapebuf = ast_str_thread_get(&thread_escapebuf, 16);
740 int ret = 0;
741 long http_code = 0; /* read curl response */
742 size_t i;
743 struct ast_vector_int hasfailurecode = { NULL };
744 char *failurecodestrings,*found;
745 CURL **curl;
746 struct curl_settings *cur;
747 struct curl_slist *headers = NULL;
748 struct ast_datastore *store = NULL;
749 int hashcompat = 0;
751 char curl_errbuf[CURL_ERROR_SIZE + 1]; /* add one to be safe */
752
753 if (!escapebuf) {
754 return -1;
755 }
756
757 if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) {
758 ast_log(LOG_ERROR, "Cannot allocate curl structure\n");
759 return -1;
760 }
761
762 if (url_is_vulnerable(args->url)) {
763 ast_log(LOG_ERROR, "URL '%s' is vulnerable to HTTP injection attacks. Aborting CURL() call.\n", args->url);
764 return -1;
765 }
766
767 if (chan) {
769 }
770
771 AST_VECTOR_INIT(&hasfailurecode, 0); /*Initialize vector*/
774 if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
775 hashcompat = (long) cur->value;
776 } else if (cur->key == CURLOPT_HTTPHEADER) {
777 headers = curl_slist_append(headers, (char*) cur->value);
778 } else if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
779 failurecodestrings = (char*) cur->value;
780 while( (found = strsep(&failurecodestrings, ",")) != NULL) {
781 AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
782 }
783 } else {
784 curl_easy_setopt(*curl, cur->key, cur->value);
785 }
786 }
788
789 if (chan) {
790 ast_channel_lock(chan);
792 ast_channel_unlock(chan);
793 if (store) {
794 list = store->data;
795 AST_LIST_LOCK(list);
796 AST_LIST_TRAVERSE(list, cur, list) {
797 if (cur->key == CURLOPT_SPECIAL_HASHCOMPAT) {
798 hashcompat = (long) cur->value;
799 } else if (cur->key == CURLOPT_HTTPHEADER) {
800 headers = curl_slist_append(headers, (char*) cur->value);
801 } else if (cur->key == CURLOPT_SPECIAL_FAILURE_CODE) {
802 failurecodestrings = (char*) cur->value;
803 while( (found = strsep(&failurecodestrings, ",")) != NULL) {
804 AST_VECTOR_APPEND(&hasfailurecode, atoi(found));
805 }
806 } else {
807 curl_easy_setopt(*curl, cur->key, cur->value);
808 }
809 }
810 }
811 }
812
813 curl_easy_setopt(*curl, CURLOPT_URL, args->url);
814 curl_easy_setopt(*curl, CURLOPT_FILE, (void *) &args->cb_data);
815
816 if (args->postdata) {
817 curl_easy_setopt(*curl, CURLOPT_POST, 1);
818 curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, args->postdata);
819 }
820
821 /* Always assign the headers - even when NULL - in case we had
822 * custom headers the last time we used this shared cURL
823 * instance */
824 curl_easy_setopt(*curl, CURLOPT_HTTPHEADER, headers);
825
826 /* Temporarily assign a buffer for curl to write errors to. */
827 curl_errbuf[0] = curl_errbuf[CURL_ERROR_SIZE] = '\0';
828 curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, curl_errbuf);
829
830 if (curl_easy_perform(*curl) != 0) {
831 ast_log(LOG_WARNING, "%s ('%s')\n", curl_errbuf, args->url);
832 }
833
834 /* Reset buffer to NULL so curl doesn't try to write to it when the
835 * buffer is deallocated. Documentation is vague about allowing NULL
836 * here, but the source allows it. See: "typecheck: allow NULL to unset
837 * CURLOPT_ERRORBUFFER" (62bcf005f4678a93158358265ba905bace33b834). */
838 curl_easy_setopt(*curl, CURLOPT_ERRORBUFFER, (char*)NULL);
839 curl_easy_getinfo (*curl, CURLINFO_RESPONSE_CODE, &http_code);
840
841 for (i = 0; i < AST_VECTOR_SIZE(&hasfailurecode); ++i) {
842 if (http_code == AST_VECTOR_GET(&hasfailurecode,i)){
843 ast_log(LOG_NOTICE, "%s%sCURL '%s' returned response code (%ld).\n",
844 chan ? ast_channel_name(chan) : "",
845 chan ? ast_channel_name(chan) : ": ",
846 args->url,
847 http_code);
848 ret=-1;
849 break;
850 }
851 }
852 AST_VECTOR_FREE(&hasfailurecode); /* Release the vector*/
853
854 if (store) {
855 AST_LIST_UNLOCK(list);
856 }
857 curl_slist_free_all(headers);
858
859 if (args->postdata) {
860 curl_easy_setopt(*curl, CURLOPT_POST, 0);
861 }
862
863 if (args->cb_data.str && ast_str_strlen(args->cb_data.str)) {
864 ast_str_trim_blanks(args->cb_data.str);
865
866 ast_debug(3, "CURL returned str='%s'\n", ast_str_buffer(args->cb_data.str));
867 if (hashcompat) {
868 char *remainder = ast_str_buffer(args->cb_data.str);
869 char *piece;
870 struct ast_str *fields = ast_str_create(ast_str_strlen(args->cb_data.str) / 2);
871 struct ast_str *values = ast_str_create(ast_str_strlen(args->cb_data.str) / 2);
872 int rowcount = 0;
873 while (fields && values && (piece = strsep(&remainder, "&"))) {
874 char *name = strsep(&piece, "=");
876 if (piece) {
877 ast_uri_decode(piece, mode);
878 }
879 ast_uri_decode(name, mode);
880 ast_str_append(&fields, 0, "%s%s", rowcount ? "," : "", ast_str_set_escapecommas(&escapebuf, 0, name, INT_MAX));
881 ast_str_append(&values, 0, "%s%s", rowcount ? "," : "", ast_str_set_escapecommas(&escapebuf, 0, S_OR(piece, ""), INT_MAX));
882 rowcount++;
883 }
884 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields));
885 ast_str_set(&args->cb_data.str, 0, "%s", ast_str_buffer(values));
886 ast_free(fields);
888 }
889 }
890
891 if (chan) {
893 }
894
895 return ret;
896}
const char * ast_channel_name(const struct ast_channel *chan)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
#define ast_channel_lock(chan)
Definition: channel.h:2968
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
#define ast_channel_unlock(chan)
Definition: channel.h:2969
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2418
static const char name[]
Definition: format_mp3.c:68
#define CURLOPT_SPECIAL_HASHCOMPAT
Definition: func_curl.c:250
static const struct ast_datastore_info curl_info
Definition: func_curl.c:256
#define CURLOPT_SPECIAL_FAILURE_CODE
Definition: func_curl.c:252
static struct ast_threadstorage thread_escapebuf
Definition: func_curl.c:704
static int url_is_vulnerable(const char *url)
Check for potential HTTP injection risk.
Definition: func_curl.c:722
static struct ast_threadstorage curl_instance
Definition: func_curl.c:703
hashcompat
Definition: func_curl.c:291
char * strsep(char **str, const char *delims)
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define NULL
Definition: resample.c:96
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
char * ast_str_set_escapecommas(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Set a dynamic string to a non-NULL terminated substring, with escaping of commas.
Definition: strings.h:1069
void ast_str_trim_blanks(struct ast_str *buf)
Trims trailing whitespace characters from an ast_str string.
Definition: strings.h:719
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:909
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
Structure used to handle boolean flags.
Definition: utils.h:199
Support for dynamic strings.
Definition: strings.h:623
Integer vector definition.
Definition: vector.h:52
void * value
Definition: func_curl.c:264
CURLoption key
Definition: func_curl.c:263
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
const struct ast_flags ast_uri_http
Definition: utils.c:719
void ast_uri_decode(char *s, struct ast_flags spec)
Decode URI, URN, URL (overwrite string)
Definition: utils.c:762
const struct ast_flags ast_uri_http_legacy
Definition: utils.c:720
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

References args, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_debug, ast_free, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_set(), ast_str_set_escapecommas(), ast_str_strlen(), ast_str_thread_get(), ast_str_trim_blanks(), ast_threadstorage_get(), ast_uri_decode(), ast_uri_http, ast_uri_http_legacy, AST_VECTOR_APPEND, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, curl_info, curl_instance, CURLOPT_SPECIAL_FAILURE_CODE, CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, HASHCOMPAT_LEGACY, curl_settings::key, LOG_ERROR, LOG_NOTICE, LOG_WARNING, name, NULL, pbx_builtin_setvar_helper(), S_OR, strsep(), thread_escapebuf, url_is_vulnerable(), and curl_settings::value.

Referenced by acf_curl_exec(), and acf_curl_write().

◆ acf_curl_write()

static int acf_curl_write ( struct ast_channel chan,
const char *  cmd,
char *  name,
const char *  value 
)
static

Definition at line 929 of file func_curl.c.

930{
931 struct curl_args curl_params = { 0, };
932 int res;
933 char *args_value = ast_strdupa(value);
935 AST_APP_ARG(file_path);
936 );
937
938 AST_STANDARD_APP_ARGS(args, args_value);
939
940 if (ast_strlen_zero(name)) {
941 ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
942 return -1;
943 }
944
945 if (ast_strlen_zero(args.file_path)) {
946 ast_log(LOG_WARNING, "CURL requires a file to write\n");
947 return -1;
948 }
949
950 curl_params.url = name;
951 curl_params.cb_data.out_file = fopen(args.file_path, "w");
952 if (!curl_params.cb_data.out_file) {
953 ast_log(LOG_WARNING, "Failed to open file %s: %s (%d)\n",
954 args.file_path,
955 strerror(errno),
956 errno);
957 return -1;
958 }
959
960 res = acf_curl_helper(chan, &curl_params);
961
962 fclose(curl_params.cb_data.out_file);
963
964 return res;
965}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int errno
FILE * out_file
If a file is being retrieved, the file to write to.
Definition: func_curl.c:661
int value
Definition: syslog.c:37

References acf_curl_helper(), args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), curl_args::cb_data, errno, LOG_WARNING, name, curl_write_callback_data::out_file, curl_args::url, and value.

◆ acf_curlopt_helper()

static int acf_curlopt_helper ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
struct ast_str **  bufstr,
ssize_t  len 
)
static

Definition at line 529 of file func_curl.c.

530{
531 struct ast_datastore *store;
532 struct global_curl_info *list[2] = { &global_curl_info, NULL };
533 struct curl_settings *cur = NULL;
534 CURLoption key;
535 enum optiontype ot;
536 int i;
537
538 if (parse_curlopt_key(data, &key, &ot)) {
539 ast_log(LOG_ERROR, "Unrecognized option: '%s'\n", data);
540 return -1;
541 }
542
543 if (chan) {
544 /* If we have a channel, we want to read the options set there before
545 falling back to the global settings */
546 ast_channel_lock(chan);
548 ast_channel_unlock(chan);
549
550 if (store) {
551 list[0] = store->data;
553 }
554 }
555
556 for (i = 0; i < 2; i++) {
557 if (!list[i]) {
558 break;
559 }
561 AST_LIST_TRAVERSE(list[i], cur, list) {
562 if (cur->key == key) {
563 if (ot == OT_BOOLEAN || ot == OT_INTEGER) {
564 if (buf) {
565 snprintf(buf, len, "%ld", (long) cur->value);
566 } else {
567 ast_str_set(bufstr, len, "%ld", (long) cur->value);
568 }
569 } else if (ot == OT_INTEGER_MS) {
570 if ((long) cur->value % 1000 == 0) {
571 if (buf) {
572 snprintf(buf, len, "%ld", (long)cur->value / 1000);
573 } else {
574 ast_str_set(bufstr, len, "%ld", (long) cur->value / 1000);
575 }
576 } else {
577 if (buf) {
578 snprintf(buf, len, "%.3f", (double) ((long) cur->value) / 1000.0);
579 } else {
580 ast_str_set(bufstr, len, "%.3f", (double) ((long) cur->value) / 1000.0);
581 }
582 }
583 } else if (ot == OT_STRING) {
584 ast_debug(1, "Found entry %p, with key %d and value %p\n", cur, cur->key, cur->value);
585 if (buf) {
587 } else {
588 ast_str_set(bufstr, 0, "%s", (char *) cur->value);
589 }
590 } else if (key == CURLOPT_PROXYTYPE) {
591 const char *strval = "unknown";
592 if (0) {
593#if CURLVERSION_ATLEAST(7,15,2)
594 } else if ((long)cur->value == CURLPROXY_SOCKS4) {
595 strval = "socks4";
596#endif
597#if CURLVERSION_ATLEAST(7,18,0)
598 } else if ((long)cur->value == CURLPROXY_SOCKS4A) {
599 strval = "socks4a";
600#endif
601 } else if ((long)cur->value == CURLPROXY_SOCKS5) {
602 strval = "socks5";
603#if CURLVERSION_ATLEAST(7,18,0)
604 } else if ((long)cur->value == CURLPROXY_SOCKS5_HOSTNAME) {
605 strval = "socks5hostname";
606#endif
607#if CURLVERSION_ATLEAST(7,10,0)
608 } else if ((long)cur->value == CURLPROXY_HTTP) {
609 strval = "http";
610#endif
611 }
612 if (buf) {
613 ast_copy_string(buf, strval, len);
614 } else {
615 ast_str_set(bufstr, 0, "%s", strval);
616 }
617 } else if (key == CURLOPT_SPECIAL_HASHCOMPAT) {
618 const char *strval = "unknown";
619 if ((long) cur->value == HASHCOMPAT_LEGACY) {
620 strval = "legacy";
621 } else if ((long) cur->value == HASHCOMPAT_YES) {
622 strval = "yes";
623 } else if ((long) cur->value == HASHCOMPAT_NO) {
624 strval = "no";
625 }
626 if (buf) {
627 ast_copy_string(buf, strval, len);
628 } else {
629 ast_str_set(bufstr, 0, "%s", strval);
630 }
631 }
632 break;
633 }
634 }
636 if (cur) {
637 break;
638 }
639 }
640
641 return cur ? 0 : -1;
642}
optiontype
Definition: func_curl.c:283
struct global_curl_info global_curl_info
static int parse_curlopt_key(const char *name, CURLoption *key, enum optiontype *ot)
Definition: func_curl.c:297
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
struct curl_settings::@168 list

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_str_set(), buf, curl_info, CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, global_curl_info, HASHCOMPAT_LEGACY, HASHCOMPAT_NO, HASHCOMPAT_YES, curl_settings::key, len(), curl_settings::list, LOG_ERROR, NULL, OT_BOOLEAN, OT_INTEGER, OT_INTEGER_MS, OT_STRING, parse_curlopt_key(), and curl_settings::value.

Referenced by acf_curlopt_read(), and acf_curlopt_read2().

◆ acf_curlopt_read()

static int acf_curlopt_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 644 of file func_curl.c.

645{
646 return acf_curlopt_helper(chan, cmd, data, buf, NULL, len);
647}
static int acf_curlopt_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, ssize_t len)
Definition: func_curl.c:529

References acf_curlopt_helper(), buf, len(), and NULL.

◆ acf_curlopt_read2()

static int acf_curlopt_read2 ( struct ast_channel chan,
const char *  cmd,
char *  data,
struct ast_str **  buf,
ssize_t  len 
)
static

Definition at line 649 of file func_curl.c.

650{
651 return acf_curlopt_helper(chan, cmd, data, NULL, buf, len);
652}

References acf_curlopt_helper(), buf, len(), and NULL.

◆ acf_curlopt_write()

static int acf_curlopt_write ( struct ast_channel chan,
const char *  cmd,
char *  name,
const char *  value 
)
static

Definition at line 399 of file func_curl.c.

400{
401 struct ast_datastore *store;
402 struct global_curl_info *list;
403 struct curl_settings *cur, *new = NULL;
404 CURLoption key;
405 enum optiontype ot;
406
407 if (chan) {
408 ast_channel_lock(chan);
409 if (!(store = ast_channel_datastore_find(chan, &curl_info, NULL))) {
410 /* Create a new datastore */
411 if (!(store = ast_datastore_alloc(&curl_info, NULL))) {
412 ast_log(LOG_ERROR, "Unable to allocate new datastore. Cannot set any CURL options\n");
413 ast_channel_unlock(chan);
414 return -1;
415 }
416
417 if (!(list = ast_calloc(1, sizeof(*list)))) {
418 ast_log(LOG_ERROR, "Unable to allocate list head. Cannot set any CURL options\n");
419 ast_datastore_free(store);
420 ast_channel_unlock(chan);
421 return -1;
422 }
423
424 store->data = list;
426 ast_channel_datastore_add(chan, store);
427 } else {
428 list = store->data;
429 }
430 ast_channel_unlock(chan);
431 } else {
432 /* Populate the global structure */
434 }
435
436 if (!parse_curlopt_key(name, &key, &ot)) {
437 if (ot == OT_BOOLEAN) {
438 if ((new = ast_calloc(1, sizeof(*new)))) {
439 new->value = (void *)((long) ast_true(value));
440 }
441 } else if (ot == OT_INTEGER) {
442 long tmp = atol(value);
443 if ((new = ast_calloc(1, sizeof(*new)))) {
444 new->value = (void *)tmp;
445 }
446 } else if (ot == OT_INTEGER_MS) {
447 long tmp = atof(value) * 1000.0;
448 if ((new = ast_calloc(1, sizeof(*new)))) {
449 new->value = (void *)tmp;
450 }
451 } else if (ot == OT_STRING) {
452 if ((new = ast_calloc(1, sizeof(*new) + strlen(value) + 1))) {
453 new->value = (char *)new + sizeof(*new);
454 strcpy(new->value, value);
455 }
456 } else if (ot == OT_ENUM) {
457 if (key == CURLOPT_PROXYTYPE) {
458 long ptype =
459#if CURLVERSION_ATLEAST(7,10,0)
460 CURLPROXY_HTTP;
461#else
462 CURLPROXY_SOCKS5;
463#endif
464 if (0) {
465#if CURLVERSION_ATLEAST(7,15,2)
466 } else if (!strcasecmp(value, "socks4")) {
467 ptype = CURLPROXY_SOCKS4;
468#endif
469#if CURLVERSION_ATLEAST(7,18,0)
470 } else if (!strcasecmp(value, "socks4a")) {
471 ptype = CURLPROXY_SOCKS4A;
472#endif
473#if CURLVERSION_ATLEAST(7,18,0)
474 } else if (!strcasecmp(value, "socks5")) {
475 ptype = CURLPROXY_SOCKS5;
476#endif
477#if CURLVERSION_ATLEAST(7,18,0)
478 } else if (!strncasecmp(value, "socks5", 6)) {
479 ptype = CURLPROXY_SOCKS5_HOSTNAME;
480#endif
481 }
482
483 if ((new = ast_calloc(1, sizeof(*new)))) {
484 new->value = (void *)ptype;
485 }
486 } else if (key == CURLOPT_SPECIAL_HASHCOMPAT) {
487 if ((new = ast_calloc(1, sizeof(*new)))) {
488 new->value = (void *) (long) (!strcasecmp(value, "legacy") ? HASHCOMPAT_LEGACY : ast_true(value) ? HASHCOMPAT_YES : HASHCOMPAT_NO);
489 }
490 } else {
491 /* Highly unlikely */
492 goto yuck;
493 }
494 }
495
496 /* Memory allocation error */
497 if (!new) {
498 return -1;
499 }
500
501 new->key = key;
502 } else {
503yuck:
504 ast_log(LOG_ERROR, "Unrecognized option: %s\n", name);
505 return -1;
506 }
507
508 /* Remove any existing entry, only http headers are left */
510 if (new->key != CURLOPT_HTTPHEADER) {
512 if (cur->key == new->key) {
514 ast_free(cur);
515 break;
516 }
517 }
519 }
520
521 /* Insert new entry */
522 ast_debug(1, "Inserting entry %p with key %d and value %p\n", new, new->key, new->value);
525
526 return 0;
527}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
static int tmp()
Definition: bt_open.c:389
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2404
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), ast_debug, ast_free, 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(), curl_info, CURLOPT_SPECIAL_HASHCOMPAT, ast_datastore::data, global_curl_info, HASHCOMPAT_LEGACY, HASHCOMPAT_NO, HASHCOMPAT_YES, curl_settings::key, curl_settings::list, LOG_ERROR, name, NULL, OT_BOOLEAN, OT_ENUM, OT_INTEGER, OT_INTEGER_MS, OT_STRING, parse_curlopt_key(), tmp(), and value.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1060 of file func_curl.c.

◆ curl_instance_cleanup()

static void curl_instance_cleanup ( void *  data)
static

Definition at line 694 of file func_curl.c.

695{
696 CURL **curl = data;
697
698 curl_easy_cleanup(*curl);
699
700 ast_free(data);
701}

References ast_free.

◆ curl_instance_init()

static int curl_instance_init ( void *  data)
static

Definition at line 679 of file func_curl.c.

680{
681 CURL **curl = data;
682
683 if (!(*curl = curl_easy_init()))
684 return -1;
685
686 curl_easy_setopt(*curl, CURLOPT_NOSIGNAL, 1);
687 curl_easy_setopt(*curl, CURLOPT_TIMEOUT, 180);
688 curl_easy_setopt(*curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
689 curl_easy_setopt(*curl, CURLOPT_USERAGENT, AST_CURL_USER_AGENT);
690
691 return 0;
692}
#define AST_CURL_USER_AGENT
Definition: asterisk.h:44
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
Definition: func_curl.c:664

References AST_CURL_USER_AGENT, and WriteMemoryCallback().

◆ curlds_free()

static void curlds_free ( void *  data)
static

Definition at line 269 of file func_curl.c.

270{
272 struct curl_settings *setting;
273 if (!list) {
274 return;
275 }
276 while ((setting = AST_LIST_REMOVE_HEAD(list, list))) {
277 ast_free(setting);
278 }
280 ast_free(list);
281}
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833

References ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_REMOVE_HEAD, and curl_settings::list.

◆ load_module()

static int load_module ( void  )
static

Definition at line 1042 of file func_curl.c.

1043{
1044 int res;
1045
1048
1049 AST_TEST_REGISTER(vulnerable_url);
1050
1051 return res;
1052}
static struct ast_custom_function acf_curlopt
Definition: func_curl.c:973
static struct ast_custom_function acf_curl
Definition: func_curl.c:967
#define ast_custom_function_register_escalating(acf, escalation)
Register a custom function which requires escalated privileges.
Definition: pbx.h:1567
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
@ AST_CFE_WRITE
Definition: pbx.h:1551
#define AST_TEST_REGISTER(cb)
Definition: test.h:127

References acf_curl, acf_curlopt, AST_CFE_WRITE, ast_custom_function_register, ast_custom_function_register_escalating, and AST_TEST_REGISTER.

◆ parse_curlopt_key()

static int parse_curlopt_key ( const char *  name,
CURLoption *  key,
enum optiontype ot 
)
static

Definition at line 297 of file func_curl.c.

298{
299 if (!strcasecmp(name, "header")) {
300 *key = CURLOPT_HEADER;
301 *ot = OT_BOOLEAN;
302 } else if (!strcasecmp(name, "httpheader")) {
303 *key = CURLOPT_HTTPHEADER;
304 *ot = OT_STRING;
305 } else if (!strcasecmp(name, "proxy")) {
306 *key = CURLOPT_PROXY;
307 *ot = OT_STRING;
308 } else if (!strcasecmp(name, "proxyport")) {
309 *key = CURLOPT_PROXYPORT;
310 *ot = OT_INTEGER;
311 } else if (!strcasecmp(name, "proxytype")) {
312 *key = CURLOPT_PROXYTYPE;
313 *ot = OT_ENUM;
314 } else if (!strcasecmp(name, "dnstimeout")) {
315 *key = CURLOPT_DNS_CACHE_TIMEOUT;
316 *ot = OT_INTEGER;
317 } else if (!strcasecmp(name, "userpwd")) {
318 *key = CURLOPT_USERPWD;
319 *ot = OT_STRING;
320 } else if (!strcasecmp(name, "proxyuserpwd")) {
321 *key = CURLOPT_PROXYUSERPWD;
322 *ot = OT_STRING;
323 } else if (!strcasecmp(name, "followlocation")) {
324 *key = CURLOPT_FOLLOWLOCATION;
325 *ot = OT_BOOLEAN;
326 } else if (!strcasecmp(name, "maxredirs")) {
327 *key = CURLOPT_MAXREDIRS;
328 *ot = OT_INTEGER;
329 } else if (!strcasecmp(name, "referer")) {
330 *key = CURLOPT_REFERER;
331 *ot = OT_STRING;
332 } else if (!strcasecmp(name, "useragent")) {
333 *key = CURLOPT_USERAGENT;
334 *ot = OT_STRING;
335 } else if (!strcasecmp(name, "cookie")) {
336 *key = CURLOPT_COOKIE;
337 *ot = OT_STRING;
338 } else if (!strcasecmp(name, "ftptimeout")) {
339 *key = CURLOPT_FTP_RESPONSE_TIMEOUT;
340 *ot = OT_INTEGER;
341 } else if (!strcasecmp(name, "httptimeout")) {
342#if CURLVERSION_ATLEAST(7,16,2)
343 *key = CURLOPT_TIMEOUT_MS;
344 *ot = OT_INTEGER_MS;
345#else
346 *key = CURLOPT_TIMEOUT;
347 *ot = OT_INTEGER;
348#endif
349 } else if (!strcasecmp(name, "conntimeout")) {
350#if CURLVERSION_ATLEAST(7,16,2)
351 *key = CURLOPT_CONNECTTIMEOUT_MS;
352 *ot = OT_INTEGER_MS;
353#else
354 *key = CURLOPT_CONNECTTIMEOUT;
355 *ot = OT_INTEGER;
356#endif
357 } else if (!strcasecmp(name, "ftptext")) {
358 *key = CURLOPT_TRANSFERTEXT;
359 *ot = OT_BOOLEAN;
360 } else if (!strcasecmp(name, "ssl_verifypeer")) {
361 *key = CURLOPT_SSL_VERIFYPEER;
362 *ot = OT_BOOLEAN;
363 } else if (!strcasecmp(name, "ssl_verifyhost")) {
364 *key = CURLOPT_SSL_VERIFYHOST;
365 *ot = OT_INTEGER;
366 } else if (!strcasecmp(name, "ssl_cainfo")) {
367 *key = CURLOPT_CAINFO;
368 *ot = OT_STRING;
369 } else if (!strcasecmp(name, "ssl_capath")) {
370 *key = CURLOPT_CAPATH;
371 *ot = OT_STRING;
372 } else if (!strcasecmp(name, "ssl_cert")) {
373 *key = CURLOPT_SSLCERT;
374 *ot = OT_STRING;
375 } else if (!strcasecmp(name, "ssl_certtype")) {
376 *key = CURLOPT_SSLCERTTYPE;
377 *ot = OT_STRING;
378 } else if (!strcasecmp(name, "ssl_key")) {
379 *key = CURLOPT_SSLKEY;
380 *ot = OT_STRING;
381 } else if (!strcasecmp(name, "ssl_keytype")) {
382 *key = CURLOPT_SSLKEYTYPE;
383 *ot = OT_STRING;
384 } else if (!strcasecmp(name, "ssl_keypasswd")) {
385 *key = CURLOPT_KEYPASSWD;
386 *ot = OT_STRING;
387 } else if (!strcasecmp(name, "hashcompat")) {
389 *ot = OT_ENUM;
390 } else if (!strcasecmp(name, "failurecodes")) {
392 *ot = OT_STRING;
393 } else {
394 return -1;
395 }
396 return 0;
397}

References CURLOPT_SPECIAL_FAILURE_CODE, CURLOPT_SPECIAL_HASHCOMPAT, curl_settings::key, name, OT_BOOLEAN, OT_ENUM, OT_INTEGER, OT_INTEGER_MS, and OT_STRING.

Referenced by acf_curlopt_helper(), and acf_curlopt_write().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1030 of file func_curl.c.

1031{
1032 int res;
1033
1036
1037 AST_TEST_UNREGISTER(vulnerable_url);
1038
1039 return res;
1040}
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

References acf_curl, acf_curlopt, ast_custom_function_unregister(), and AST_TEST_UNREGISTER.

◆ url_is_vulnerable()

static int url_is_vulnerable ( const char *  url)
static

Check for potential HTTP injection risk.

CVE-2014-8150 brought up the fact that HTTP proxies are subject to injection attacks. An HTTP URL sent to a proxy contains a carriage-return linefeed combination, followed by a complete HTTP request. Proxies will handle this as two separate HTTP requests rather than as a malformed URL.

libcURL patched this vulnerability in version 7.40.0, but we have no guarantee that Asterisk systems will be using an up-to-date cURL library. Therefore, we implement the same fix as libcURL for determining if a URL is vulnerable to an injection attack.

Parameters
urlThe URL to check for vulnerability
Return values
0The URL is not vulnerable
1The URL is vulnerable.

Definition at line 722 of file func_curl.c.

723{
724 if (strpbrk(url, "\r\n")) {
725 return 1;
726 }
727
728 return 0;
729}

References url.

Referenced by acf_curl_helper().

◆ WriteMemoryCallback()

static size_t WriteMemoryCallback ( void *  ptr,
size_t  size,
size_t  nmemb,
void *  data 
)
static

Definition at line 664 of file func_curl.c.

665{
666 register int realsize = 0;
667 struct curl_write_callback_data *cb_data = data;
668
669 if (cb_data->str) {
670 realsize = size * nmemb;
671 ast_str_append_substr(&cb_data->str, 0, ptr, realsize);
672 } else if (cb_data->out_file) {
673 realsize = fwrite(ptr, size, nmemb, cb_data->out_file);
674 }
675
676 return realsize;
677}
char * ast_str_append_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string.
Definition: strings.h:1062
Callback data passed to WriteMemoryCallback.
Definition: func_curl.c:655

References ast_str_append_substr(), curl_write_callback_data::out_file, and curl_write_callback_data::str.

Referenced by curl_instance_init().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Load external URL" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_REALTIME_DEPEND2, .requires = "res_curl", }
static

Definition at line 1060 of file func_curl.c.

◆ acf_curl

struct ast_custom_function acf_curl
static
Initial value:
= {
.name = "CURL",
.read2 = acf_curl_exec,
.write = acf_curl_write,
}
static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len)
Definition: func_curl.c:898
static int acf_curl_write(struct ast_channel *chan, const char *cmd, char *name, const char *value)
Definition: func_curl.c:929

Definition at line 967 of file func_curl.c.

Referenced by load_module(), and unload_module().

◆ acf_curlopt

struct ast_custom_function acf_curlopt
static

Definition at line 973 of file func_curl.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1060 of file func_curl.c.

◆ curl_info

const struct ast_datastore_info curl_info
static
Initial value:
= {
.type = "CURL",
.destroy = curlds_free,
}
static void curlds_free(void *data)
Definition: func_curl.c:269

Definition at line 256 of file func_curl.c.

Referenced by acf_curl_helper(), acf_curlopt_helper(), and acf_curlopt_write().

◆ curl_instance

struct ast_threadstorage curl_instance = { .once = PTHREAD_ONCE_INIT , .key_init = __init_curl_instance , .custom_init = curl_instance_init , }
static

Definition at line 703 of file func_curl.c.

Referenced by acf_curl_helper().

◆ global_curl_info

struct global_curl_info global_curl_info = { .first = NULL, .last = NULL, .lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} } , }

◆ thread_escapebuf

struct ast_threadstorage thread_escapebuf = { .once = PTHREAD_ONCE_INIT , .key_init = __init_thread_escapebuf , .custom_init = NULL , }
static

Definition at line 704 of file func_curl.c.

Referenced by acf_curl_helper().