Wed Jan 8 2020 09:49:47

Asterisk developer's documentation


func_global.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2006, Tilghman Lesher
5  *
6  * Tilghman Lesher <func_global__200605@the-tilghman.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Global variable dialplan functions
22  *
23  * \author Tilghman Lesher <func_global__200605@the-tilghman.com>
24  *
25  * \ingroup functions
26  */
27 
28 /*** MODULEINFO
29  <support_level>core</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 411313 $")
35 
36 #include <sys/stat.h>
37 
38 #include "asterisk/module.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/app.h"
42 #include "asterisk/manager.h"
43 
44 /*** DOCUMENTATION
45  <function name="GLOBAL" language="en_US">
46  <synopsis>
47  Gets or sets the global variable specified.
48  </synopsis>
49  <syntax>
50  <parameter name="varname" required="true">
51  <para>Global variable name</para>
52  </parameter>
53  </syntax>
54  <description>
55  <para>Set or get the value of a global variable specified in <replaceable>varname</replaceable></para>
56  </description>
57  </function>
58  <function name="SHARED" language="en_US">
59  <synopsis>
60  Gets or sets the shared variable specified.
61  </synopsis>
62  <syntax>
63  <parameter name="varname" required="true">
64  <para>Variable name</para>
65  </parameter>
66  <parameter name="channel">
67  <para>If not specified will default to current channel. It is the complete
68  channel name: <literal>SIP/12-abcd1234</literal> or the prefix only <literal>SIP/12</literal>.</para>
69  </parameter>
70  </syntax>
71  <description>
72  <para>Implements a shared variable area, in which you may share variables between
73  channels.</para>
74  <para>The variables used in this space are separate from the general namespace of
75  the channel and thus <variable>SHARED(foo)</variable> and <variable>foo</variable>
76  represent two completely different variables, despite sharing the same name.</para>
77  <para>Finally, realize that there is an inherent race between channels operating
78  at the same time, fiddling with each others' internal variables, which is why
79  this special variable namespace exists; it is to remind you that variables in
80  the SHARED namespace may change at any time, without warning. You should
81  therefore take special care to ensure that when using the SHARED namespace,
82  you retrieve the variable and store it in a regular channel variable before
83  using it in a set of calculations (or you might be surprised by the result).</para>
84  </description>
85  </function>
86 
87  ***/
88 
89 static void shared_variable_free(void *data);
90 
92  .type = "SHARED_VARIABLES",
93  .destroy = shared_variable_free,
94 };
95 
96 static void shared_variable_free(void *data)
97 {
98  struct varshead *varshead = data;
99  struct ast_var_t *var;
100 
101  while ((var = AST_LIST_REMOVE_HEAD(varshead, entries))) {
102  ast_var_delete(var);
103  }
104  ast_free(varshead);
105 }
106 
107 static int global_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
108 {
109  const char *var = pbx_builtin_getvar_helper(NULL, data);
110 
111  *buf = '\0';
112 
113  if (var)
114  ast_copy_string(buf, var, len);
115 
116  return 0;
117 }
118 
119 static int global_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
120 {
121  pbx_builtin_setvar_helper(NULL, data, value);
122 
123  return 0;
124 }
125 
127  .name = "GLOBAL",
128  .read = global_read,
129  .write = global_write,
130 };
131 
132 static int shared_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
133 {
134  struct ast_datastore *varstore;
135  struct varshead *varshead;
136  struct ast_var_t *var;
138  AST_APP_ARG(var);
139  AST_APP_ARG(chan);
140  );
141  struct ast_channel *c_ref = NULL;
142 
143  if (ast_strlen_zero(data)) {
144  ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
145  return -1;
146  }
147 
149 
150  if (!ast_strlen_zero(args.chan)) {
151  char *prefix = ast_alloca(strlen(args.chan) + 2);
152  sprintf(prefix, "%s-", args.chan);
153  if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
154  ast_log(LOG_ERROR, "Channel '%s' not found! Variable '%s' will be blank.\n", args.chan, args.var);
155  return -1;
156  }
157  chan = c_ref;
158  } else if (!chan) {
159  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
160  return -1;
161  }
162 
163  ast_channel_lock(chan);
164 
165  if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
166  ast_channel_unlock(chan);
167  if (c_ref) {
168  c_ref = ast_channel_unref(c_ref);
169  }
170  return -1;
171  }
172 
173  varshead = varstore->data;
174  *buf = '\0';
175 
176  /* Protected by the channel lock */
177  AST_LIST_TRAVERSE(varshead, var, entries) {
178  if (!strcmp(args.var, ast_var_name(var))) {
179  ast_copy_string(buf, ast_var_value(var), len);
180  break;
181  }
182  }
183 
184  ast_channel_unlock(chan);
185 
186  if (c_ref) {
187  c_ref = ast_channel_unref(c_ref);
188  }
189 
190  return 0;
191 }
192 
193 static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
194 {
195  struct ast_datastore *varstore;
196  struct varshead *varshead;
197  struct ast_var_t *var;
199  AST_APP_ARG(var);
200  AST_APP_ARG(chan);
201  );
202  struct ast_channel *c_ref = NULL;
203 
204  if (ast_strlen_zero(data)) {
205  ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
206  return -1;
207  }
208 
210 
211  if (!ast_strlen_zero(args.chan)) {
212  char *prefix = ast_alloca(strlen(args.chan) + 2);
213  sprintf(prefix, "%s-", args.chan);
214  if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
215  ast_log(LOG_ERROR, "Channel '%s' not found! Variable '%s' not set to '%s'.\n", args.chan, args.var, value);
216  return -1;
217  }
218  chan = c_ref;
219  } else if (!chan) {
220  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
221  return -1;
222  }
223 
224  ast_channel_lock(chan);
225 
226  if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
227  if (!(varstore = ast_datastore_alloc(&shared_variable_info, NULL))) {
228  ast_log(LOG_ERROR, "Unable to allocate new datastore. Shared variable not set.\n");
229  ast_channel_unlock(chan);
230  if (c_ref) {
231  c_ref = ast_channel_unref(c_ref);
232  }
233  return -1;
234  }
235 
236  if (!(varshead = ast_calloc(1, sizeof(*varshead)))) {
237  ast_log(LOG_ERROR, "Unable to allocate variable structure. Shared variable not set.\n");
238  ast_datastore_free(varstore);
239  ast_channel_unlock(chan);
240  if (c_ref) {
241  c_ref = ast_channel_unref(c_ref);
242  }
243  return -1;
244  }
245 
246  varstore->data = varshead;
247  ast_channel_datastore_add(chan, varstore);
248  }
249  varshead = varstore->data;
250 
251  /* Protected by the channel lock */
252  AST_LIST_TRAVERSE_SAFE_BEGIN(varshead, var, entries) {
253  /* If there's a previous value, remove it */
254  if (!strcmp(args.var, ast_var_name(var))) {
255  AST_LIST_REMOVE_CURRENT(entries);
256  ast_var_delete(var);
257  break;
258  }
259  }
261 
262  if ((var = ast_var_assign(args.var, S_OR(value, "")))) {
263  AST_LIST_INSERT_HEAD(varshead, var, entries);
265  "Channel: %s\r\n"
266  "Variable: SHARED(%s)\r\n"
267  "Value: %s\r\n"
268  "Uniqueid: %s\r\n",
269  chan ? chan->name : "none", args.var, value,
270  chan ? chan->uniqueid : "none");
271  }
272 
273  ast_channel_unlock(chan);
274 
275  if (c_ref) {
276  c_ref = ast_channel_unref(c_ref);
277  }
278 
279  return 0;
280 }
281 
283  .name = "SHARED",
284  .read = shared_read,
285  .write = shared_write,
286 };
287 
288 static int unload_module(void)
289 {
290  int res = 0;
291 
292  res |= ast_custom_function_unregister(&global_function);
293  res |= ast_custom_function_unregister(&shared_function);
294 
295  return res;
296 }
297 
298 static int load_module(void)
299 {
300  int res = 0;
301 
302  res |= ast_custom_function_register(&global_function);
303  res |= ast_custom_function_register(&shared_function);
304 
305  return res;
306 }
307 
308 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Variable dialplan functions");
const char * type
Definition: datastore.h:32
#define ast_channel_lock(chan)
Definition: channel.h:2466
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
Asterisk main include file. File version handling, generic pbx functions.
const ast_string_field uniqueid
Definition: channel.h:787
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:89
struct ast_var_t * ast_var_assign(const char *name, const char *value)
Definition: chanvars.c:41
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:69
#define LOG_WARNING
Definition: logger.h:144
static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition: func_global.c:193
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
#define var
Definition: ast_expr2f.c:606
Structure for a data store type.
Definition: datastore.h:31
Structure for a data store object.
Definition: datastore.h:54
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:2604
static struct ast_datastore_info shared_variable_info
Definition: func_global.c:91
const char * data
Definition: channel.h:755
int value
Definition: syslog.c:39
static int unload_module(void)
Definition: func_global.c:288
#define EVENT_FLAG_DIALPLAN
Definition: manager.h:82
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
void ast_var_delete(struct ast_var_t *var)
Definition: chanvars.c:63
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Definition: pbx.c:3814
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:65
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Definition: pbx.c:10475
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition: channel.c:1808
static int global_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_global.c:107
static int shared_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_global.c:132
static struct ast_custom_function shared_function
Definition: func_global.c:282
General Asterisk PBX channel definitions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
Data structure associated with a custom dialplan function.
Definition: pbx.h:95
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:554
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
Core PBX routines and definitions.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define LOG_ERROR
Definition: logger.h:155
static struct @350 args
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
Definition: datastore.c:98
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:696
#define ast_channel_unlock(chan)
Definition: channel.h:2467
struct ast_var_t::@158 entries
#define ast_free(a)
Definition: astmm.h:97
static int load_module(void)
Definition: func_global.c:298
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...
Definition: pbx.c:10546
void * data
Definition: datastore.h:56
static void shared_variable_free(void *data)
Definition: func_global.c:96
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static struct ast_custom_function global_function
Definition: func_global.c:126
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
const char * name
Definition: pbx.h:96
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
static int global_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition: func_global.c:119
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition: manager.h:219
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1803
Asterisk module definitions.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2590
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1164
struct varshead varshead
Definition: channel.h:817
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
static char prefix[MAX_PREFIX]
Definition: http.c:107