Asterisk - The Open Source Telephony Project  GIT-master-a1fa8df
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 #include <sys/stat.h>
35 
36 #include "asterisk/module.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/app.h"
41 
42 /*** DOCUMENTATION
43  <function name="GLOBAL" language="en_US">
44  <synopsis>
45  Gets or sets the global variable specified.
46  </synopsis>
47  <syntax>
48  <parameter name="varname" required="true">
49  <para>Global variable name</para>
50  </parameter>
51  </syntax>
52  <description>
53  <para>Set or get the value of a global variable specified in <replaceable>varname</replaceable></para>
54  </description>
55  </function>
56  <function name="SHARED" language="en_US">
57  <synopsis>
58  Gets or sets the shared variable specified.
59  </synopsis>
60  <syntax>
61  <parameter name="varname" required="true">
62  <para>Variable name</para>
63  </parameter>
64  <parameter name="channel">
65  <para>If not specified will default to current channel. It is the complete
66  channel name: <literal>SIP/12-abcd1234</literal> or the prefix only <literal>SIP/12</literal>.</para>
67  </parameter>
68  </syntax>
69  <description>
70  <para>Implements a shared variable area, in which you may share variables between
71  channels.</para>
72  <para>The variables used in this space are separate from the general namespace of
73  the channel and thus <variable>SHARED(foo)</variable> and <variable>foo</variable>
74  represent two completely different variables, despite sharing the same name.</para>
75  <para>Finally, realize that there is an inherent race between channels operating
76  at the same time, fiddling with each others' internal variables, which is why
77  this special variable namespace exists; it is to remind you that variables in
78  the SHARED namespace may change at any time, without warning. You should
79  therefore take special care to ensure that when using the SHARED namespace,
80  you retrieve the variable and store it in a regular channel variable before
81  using it in a set of calculations (or you might be surprised by the result).</para>
82  </description>
83  </function>
84  <managerEvent language="en_US" name="VarSet">
85  <managerEventInstance class="EVENT_FLAG_DIALPLAN">
86  <synopsis>Raised when a variable is shared between channels.</synopsis>
87  <syntax>
88  <channel_snapshot/>
89  <parameter name="Variable">
90  <para>The SHARED variable being set.</para>
91  <note><para>The variable name will always be enclosed with
92  <literal>SHARED()</literal></para></note>
93  </parameter>
94  <parameter name="Value">
95  <para>The new value of the variable.</para>
96  </parameter>
97  </syntax>
98  <see-also>
99  <ref type="function">SHARED</ref>
100  </see-also>
101  </managerEventInstance>
102  </managerEvent>
103  ***/
104 
105 static void shared_variable_free(void *data);
106 
108  .type = "SHARED_VARIABLES",
109  .destroy = shared_variable_free,
110 };
111 
112 static void shared_variable_free(void *data)
113 {
114  struct varshead *varshead = data;
115  struct ast_var_t *var;
116 
117  while ((var = AST_LIST_REMOVE_HEAD(varshead, entries))) {
118  ast_var_delete(var);
119  }
120  ast_free(varshead);
121 }
122 
123 static int global_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
124 {
125  const char *var = pbx_builtin_getvar_helper(NULL, data);
126 
127  *buf = '\0';
128 
129  if (var)
130  ast_copy_string(buf, var, len);
131 
132  return 0;
133 }
134 
135 static int global_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
136 {
137  pbx_builtin_setvar_helper(NULL, data, value);
138 
139  return 0;
140 }
141 
143  .name = "GLOBAL",
144  .read = global_read,
145  .write = global_write,
146 };
147 
148 static int shared_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
149 {
150  struct ast_datastore *varstore;
151  struct varshead *varshead;
152  struct ast_var_t *var;
154  AST_APP_ARG(var);
155  AST_APP_ARG(chan);
156  );
157  struct ast_channel *c_ref = NULL;
158 
159  if (ast_strlen_zero(data)) {
160  ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
161  return -1;
162  }
163 
165 
166  if (!ast_strlen_zero(args.chan)) {
167  char *prefix = ast_alloca(strlen(args.chan) + 2);
168  sprintf(prefix, "%s-", args.chan);
169  if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
170  ast_log(LOG_ERROR, "Channel '%s' not found! Variable '%s' will be blank.\n", args.chan, args.var);
171  return -1;
172  }
173  chan = c_ref;
174  } else if (!chan) {
175  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
176  return -1;
177  }
178 
179  ast_channel_lock(chan);
180 
181  if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
182  ast_channel_unlock(chan);
183  if (c_ref) {
184  c_ref = ast_channel_unref(c_ref);
185  }
186  return -1;
187  }
188 
189  varshead = varstore->data;
190  *buf = '\0';
191 
192  /* Protected by the channel lock */
193  AST_LIST_TRAVERSE(varshead, var, entries) {
194  if (!strcmp(args.var, ast_var_name(var))) {
195  ast_copy_string(buf, ast_var_value(var), len);
196  break;
197  }
198  }
199 
200  ast_channel_unlock(chan);
201 
202  if (c_ref) {
203  c_ref = ast_channel_unref(c_ref);
204  }
205 
206  return 0;
207 }
208 
209 static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
210 {
211  struct ast_datastore *varstore;
212  struct varshead *varshead;
213  struct ast_var_t *var;
215  AST_APP_ARG(var);
216  AST_APP_ARG(chan);
217  );
218  struct ast_channel *c_ref = NULL;
219  int len;
220  RAII_VAR(char *, shared_buffer, NULL, ast_free);
221 
222  if (ast_strlen_zero(data)) {
223  ast_log(LOG_WARNING, "SHARED() requires an argument: SHARED(<var>[,<chan>])\n");
224  return -1;
225  }
226 
228 
229  if (!ast_strlen_zero(args.chan)) {
230  char *prefix = ast_alloca(strlen(args.chan) + 2);
231  sprintf(prefix, "%s-", args.chan);
232  if (!(c_ref = ast_channel_get_by_name(args.chan)) && !(c_ref = ast_channel_get_by_name_prefix(prefix, strlen(prefix)))) {
233  ast_log(LOG_ERROR, "Channel '%s' not found! Variable '%s' not set to '%s'.\n", args.chan, args.var, value);
234  return -1;
235  }
236  chan = c_ref;
237  } else if (!chan) {
238  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
239  return -1;
240  }
241 
242  len = 9 + strlen(args.var); /* SHARED() + var */
243  shared_buffer = ast_malloc(len);
244  if (!shared_buffer) {
245  if (c_ref) {
246  ast_channel_unref(c_ref);
247  }
248  return -1;
249  }
250 
251  ast_channel_lock(chan);
252 
253  if (!(varstore = ast_channel_datastore_find(chan, &shared_variable_info, NULL))) {
254  if (!(varstore = ast_datastore_alloc(&shared_variable_info, NULL))) {
255  ast_log(LOG_ERROR, "Unable to allocate new datastore. Shared variable not set.\n");
256  ast_channel_unlock(chan);
257  if (c_ref) {
258  c_ref = ast_channel_unref(c_ref);
259  }
260  return -1;
261  }
262 
263  if (!(varshead = ast_calloc(1, sizeof(*varshead)))) {
264  ast_log(LOG_ERROR, "Unable to allocate variable structure. Shared variable not set.\n");
265  ast_datastore_free(varstore);
266  ast_channel_unlock(chan);
267  if (c_ref) {
268  c_ref = ast_channel_unref(c_ref);
269  }
270  return -1;
271  }
272 
273  varstore->data = varshead;
274  ast_channel_datastore_add(chan, varstore);
275  }
276  varshead = varstore->data;
277 
278  /* Protected by the channel lock */
279  AST_LIST_TRAVERSE_SAFE_BEGIN(varshead, var, entries) {
280  /* If there's a previous value, remove it */
281  if (!strcmp(args.var, ast_var_name(var))) {
282  AST_LIST_REMOVE_CURRENT(entries);
283  ast_var_delete(var);
284  break;
285  }
286  }
288 
289  if ((var = ast_var_assign(args.var, S_OR(value, "")))) {
290  AST_LIST_INSERT_HEAD(varshead, var, entries);
291 
292  sprintf(shared_buffer, "SHARED(%s)", args.var);
293  ast_channel_publish_varset(chan, shared_buffer, value);
294  }
295 
296  ast_channel_unlock(chan);
297 
298  if (c_ref) {
299  c_ref = ast_channel_unref(c_ref);
300  }
301 
302  return 0;
303 }
304 
306  .name = "SHARED",
307  .read = shared_read,
308  .write = shared_write,
309 };
310 
311 static int unload_module(void)
312 {
313  int res = 0;
314 
315  res |= ast_custom_function_unregister(&global_function);
316  res |= ast_custom_function_unregister(&shared_function);
317 
318  return res;
319 }
320 
321 static int load_module(void)
322 {
323  int res = 0;
324 
325  res |= ast_custom_function_register(&global_function);
326  res |= ast_custom_function_register(&shared_function);
327 
328  return res;
329 }
330 
331 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Variable dialplan functions");
const char * name
Definition: pbx.h:119
const char * type
Definition: datastore.h:32
#define ast_channel_lock(chan)
Definition: channel.h:2913
Main Channel structure associated with a channel.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
Asterisk main include file. File version handling, generic pbx functions.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2949
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:80
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
static int shared_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition: func_global.c:209
#define var
Definition: ast_expr2f.c:614
Structure for a data store type.
Definition: datastore.h:31
Structure for a data store object.
Definition: datastore.h:68
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:2400
const char * args
#define NULL
Definition: resample.c:96
const char * data
int value
Definition: syslog.c:37
static int unload_module(void)
Definition: func_global.c:311
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
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:1430
static int global_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_global.c:123
#define ast_log
Definition: astobj2.c:42
static int shared_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_global.c:148
static struct ast_custom_function shared_function
Definition: func_global.c:305
General Asterisk PBX channel definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
Core PBX routines and definitions.
static const struct ast_datastore_info shared_variable_info
Definition: func_global.c:107
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
#define LOG_ERROR
Definition: logger.h:285
void ast_channel_publish_varset(struct ast_channel *chan, const char *variable, const char *value)
Publish a ast_channel_varset for a channel.
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2473
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#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:710
#define ast_channel_unlock(chan)
Definition: channel.h:2914
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define ast_var_assign(name, value)
Definition: chanvars.h:40
static int load_module(void)
Definition: func_global.c:321
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...
void * data
Definition: datastore.h:70
static void shared_variable_free(void *data)
Definition: func_global.c:112
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static struct ast_custom_function global_function
Definition: func_global.c:142
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
static int global_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Definition: func_global.c:135
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1450
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:2386
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ast_var_t::@236 entries
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
struct varshead varshead
static char prefix[MAX_PREFIX]
Definition: http.c:141
#define AST_APP_ARG(name)
Define an application argument.