Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
refer.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2023, Commend International
5 *
6 * Maximilian Fridrich <m.fridrich@commend.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 Out-of-call refer support
22 *
23 * \author Maximilian Fridrich <m.fridrich@commend.com>
24 */
25
26/*** MODULEINFO
27 <support_level>core</support_level>
28 ***/
29
30#include "asterisk.h"
31
32#include "asterisk/_private.h"
33
34#include "asterisk/module.h"
35#include "asterisk/datastore.h"
36#include "asterisk/pbx.h"
37#include "asterisk/manager.h"
38#include "asterisk/strings.h"
39#include "asterisk/astobj2.h"
40#include "asterisk/vector.h"
41#include "asterisk/app.h"
43#include "asterisk/refer.h"
44
45struct refer_data {
46 /* Stored in stuff[] at struct end */
47 char *name;
48 /* Stored separately */
49 char *value;
50 /* Holds name */
51 char stuff[0];
52};
53
54/*!
55 * \brief A refer.
56 */
57struct ast_refer {
59 /*! Where the refer is going */
61 /*! Where we "say" the refer came from */
63 /*! Where to refer to */
65 /*! An endpoint associated with this refer */
67 /*! The technology of the endpoint associated with this refer */
69 );
70 /* Whether to refer to Asterisk itself, if refer_to is an Asterisk endpoint. */
72 /*! Technology/dialplan specific variables associated with the refer */
74};
75
76/*! \brief Lock for \c refer_techs vector */
78
79/*! \brief Vector of refer technologies */
81
82static int refer_data_cmp_fn(void *obj, void *arg, int flags)
83{
84 const struct refer_data *object_left = obj;
85 const struct refer_data *object_right = arg;
86 const char *right_key = arg;
87 int cmp;
88
89 switch (flags & OBJ_SEARCH_MASK) {
91 right_key = object_right->name;
92 case OBJ_SEARCH_KEY:
93 cmp = strcasecmp(object_left->name, right_key);
94 break;
96 cmp = strncasecmp(object_left->name, right_key, strlen(right_key));
97 break;
98 default:
99 cmp = 0;
100 break;
101 }
102 if (cmp) {
103 return 0;
104 }
105 return CMP_MATCH;
106}
107
108static void refer_data_destructor(void *obj)
109{
110 struct refer_data *data = obj;
111 ast_free(data->value);
112}
113
114static void refer_destructor(void *obj)
115{
116 struct ast_refer *refer = obj;
117
119 ao2_cleanup(refer->vars);
120}
121
123{
124 struct ast_refer *refer;
125
126 if (!(refer = ao2_alloc_options(sizeof(*refer), refer_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK))) {
127 return NULL;
128 }
129
130 if (ast_string_field_init(refer, 128)) {
131 ao2_ref(refer, -1);
132 return NULL;
133 }
134
137 if (!refer->vars) {
138 ao2_ref(refer, -1);
139 return NULL;
140 }
141 refer->to_self = 0;
142
143 return refer;
144}
145
146struct ast_refer *ast_refer_ref(struct ast_refer *refer)
147{
148 ao2_ref(refer, 1);
149 return refer;
150}
151
153{
154 ao2_ref(refer, -1);
155 return NULL;
156}
157
158int ast_refer_set_to(struct ast_refer *refer, const char *fmt, ...)
159{
160 va_list ap;
161
162 va_start(ap, fmt);
163 ast_string_field_build_va(refer, to, fmt, ap);
164 va_end(ap);
165
166 return 0;
167}
168
169int ast_refer_set_from(struct ast_refer *refer, const char *fmt, ...)
170{
171 va_list ap;
172
173 va_start(ap, fmt);
174 ast_string_field_build_va(refer, from, fmt, ap);
175 va_end(ap);
176
177 return 0;
178}
179
180int ast_refer_set_refer_to(struct ast_refer *refer, const char *fmt, ...)
181{
182 va_list ap;
183
184 va_start(ap, fmt);
185 ast_string_field_build_va(refer, refer_to, fmt, ap);
186 va_end(ap);
187
188 return 0;
189}
190
191int ast_refer_set_to_self(struct ast_refer *refer, int val)
192{
193 refer->to_self = val;
194 return 0;
195}
196
197int ast_refer_set_tech(struct ast_refer *refer, const char *fmt, ...)
198{
199 va_list ap;
200
201 va_start(ap, fmt);
202 ast_string_field_build_va(refer, tech, fmt, ap);
203 va_end(ap);
204
205 return 0;
206}
207
208int ast_refer_set_endpoint(struct ast_refer *refer, const char *fmt, ...)
209{
210 va_list ap;
211
212 va_start(ap, fmt);
213 ast_string_field_build_va(refer, endpoint, fmt, ap);
214 va_end(ap);
215
216 return 0;
217}
218
219const char *ast_refer_get_refer_to(const struct ast_refer *refer)
220{
221 return refer->refer_to;
222}
223
224const char *ast_refer_get_from(const struct ast_refer *refer)
225{
226 return refer->from;
227}
228
229const char *ast_refer_get_to(const struct ast_refer *refer)
230{
231 return refer->to;
232}
233
234int ast_refer_get_to_self(const struct ast_refer *refer)
235{
236 return refer->to_self;
237}
238
239const char *ast_refer_get_tech(const struct ast_refer *refer)
240{
241 return refer->tech;
242}
243
244const char *ast_refer_get_endpoint(const struct ast_refer *refer)
245{
246 return refer->endpoint;
247}
248
249static struct refer_data *refer_data_new(const char *name)
250{
251 struct refer_data *data;
252 int name_len = strlen(name) + 1;
253
254 if ((data = ao2_alloc_options(name_len + sizeof(*data), refer_data_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK))) {
255 data->name = data->stuff;
256 strcpy(data->name, name);
257 }
258
259 return data;
260}
261
262static struct refer_data *refer_data_find(struct ao2_container *vars, const char *name)
263{
264 return ao2_find(vars, name, OBJ_SEARCH_KEY);
265}
266
268{
269 struct refer_data *data;
270 char *val = NULL;
271
272 if (!(data = ao2_find(refer->vars, name, OBJ_SEARCH_KEY | OBJ_UNLINK))) {
273 return NULL;
274 }
275
276 val = ast_strdup(data->value);
277 ao2_ref(data, -1);
278
279 return val;
280}
281
282static int refer_set_var_full(struct ast_refer *refer, const char *name, const char *value)
283{
284 struct refer_data *data;
285
286 if (!(data = refer_data_find(refer->vars, name))) {
287 if (ast_strlen_zero(value)) {
288 return 0;
289 }
290 if (!(data = refer_data_new(name))) {
291 return -1;
292 };
293 data->value = ast_strdup(value);
294
295 ao2_link(refer->vars, data);
296 } else {
297 if (ast_strlen_zero(value)) {
298 ao2_unlink(refer->vars, data);
299 } else {
300 ast_free(data->value);
301 data->value = ast_strdup(value);
302 }
303 }
304
305 ao2_ref(data, -1);
306
307 return 0;
308}
309
310int ast_refer_set_var_outbound(struct ast_refer *refer, const char *name, const char *value)
311{
313}
314
315const char *ast_refer_get_var(struct ast_refer *refer, const char *name)
316{
317 struct refer_data *data;
318 const char *val = NULL;
319
320 if (!(data = refer_data_find(refer->vars, name))) {
321 return NULL;
322 }
323
324 val = data->value;
325 ao2_ref(data, -1);
326
327 return val;
328}
329
333};
334
336{
338
339 iter = ast_calloc(1, sizeof(*iter));
340 if (!iter) {
341 return NULL;
342 }
343
344 iter->iter = ao2_iterator_init(refer->vars, 0);
345
346 return iter;
347}
348
349int ast_refer_var_iterator_next(struct ast_refer_var_iterator *iter, const char **name, const char **value)
350{
351 struct refer_data *data;
352
353 if (!iter) {
354 return 0;
355 }
356
357 data = ao2_iterator_next(&iter->iter);
358 if (!data) {
359 return 0;
360 }
361
362 *name = data->name;
363 *value = data->value;
364
365 iter->current_used = data;
366
367 return 1;
368}
369
371{
373 iter->current_used = NULL;
374}
375
377{
378 if (iter) {
381 ast_free(iter);
382 }
383}
384
385/*!
386 * \internal \brief Find a \c ast_refer_tech by its technology name
387 *
388 * \param tech_name The name of the refer technology
389 *
390 * \note \c refer_techs should be locked via \c refer_techs_lock prior to
391 * calling this function
392 *
393 * \retval NULL if no \ref ast_refer_tech has been registered
394 * \return \ref ast_refer_tech if registered
395 */
396static const struct ast_refer_tech *refer_find_by_tech_name(const char *tech_name)
397{
398 const struct ast_refer_tech *current;
399 int i;
400
401 for (i = 0; i < AST_VECTOR_SIZE(&refer_techs); i++) {
403 if (!strcmp(current->name, tech_name)) {
404 return current;
405 }
406 }
407
408 return NULL;
409}
410
411int ast_refer_send(struct ast_refer *refer)
412{
413 char *tech_name = NULL;
414 const struct ast_refer_tech *refer_tech;
415 int res = -1;
416
417 if (ast_strlen_zero(refer->to)) {
418 ao2_ref(refer, -1);
419 return -1;
420 }
421
422 tech_name = ast_strdupa(refer->to);
423 tech_name = strsep(&tech_name, ":");
424
427
428 if (!refer_tech) {
429 ast_log(LOG_ERROR, "Unknown refer tech: %s\n", tech_name);
431 ao2_ref(refer, -1);
432 return -1;
433 }
434
435 ao2_lock(refer);
436 res = refer_tech->refer_send(refer);
437 ao2_unlock(refer);
438
440
441 ao2_ref(refer, -1);
442
443 return res;
444}
445
447{
448 const struct ast_refer_tech *match;
449
451
453 if (match) {
454 ast_log(LOG_ERROR, "Refer technology already registered for '%s'\n",
455 tech->name);
457 return -1;
458 }
459
460 if (AST_VECTOR_APPEND(&refer_techs, tech)) {
461 ast_log(LOG_ERROR, "Failed to register refer technology for '%s'\n",
462 tech->name);
464 return -1;
465 }
466 ast_verb(5, "Refer technology '%s' registered.\n", tech->name);
467
469
470 return 0;
471}
472
473/*!
474 * \brief Comparison callback for \c ast_refer_tech vector removal
475 *
476 * \param vec_elem The element in the vector being compared
477 * \param srch The element being looked up
478 *
479 * \retval non-zero The items are equal
480 * \retval 0 The items are not equal
481 */
482static int refer_tech_cmp(const struct ast_refer_tech *vec_elem, const struct ast_refer_tech *srch)
483{
484 if (!vec_elem->name || !srch->name) {
485 return (vec_elem->name == srch->name) ? 1 : 0;
486 }
487 return !strcmp(vec_elem->name, srch->name);
488}
489
491{
492 int match;
493
498
499 if (match) {
500 ast_log(LOG_ERROR, "No '%s' refer technology found.\n", tech->name);
501 return -1;
502 }
503
504 ast_verb(5, "Refer technology '%s' unregistered.\n", tech->name);
505
506 return 0;
507}
508
509/*!
510 * \internal
511 * \brief Clean up other resources on Asterisk shutdown
512 */
513static void refer_shutdown(void)
514{
517}
518
519/*!
520 * \internal
521 * \brief Initialize stuff during Asterisk startup.
522 *
523 * Cleanup isn't a big deal in this function. If we return non-zero,
524 * Asterisk is going to exit.
525 *
526 * \retval 0 success
527 * \retval non-zero failure
528 */
530{
532 if (AST_VECTOR_INIT(&refer_techs, 8)) {
533 return -1;
534 }
536 return 0;
537}
Prototypes for public functions only of internal interest,.
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_UNLINK
Definition: astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2362
Asterisk datastore objects.
static const char name[]
Definition: format_mp3.c:68
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
char * strsep(char **str, const char *delims)
#define LOG_ERROR
#define ast_verb(level,...)
#define ast_rwlock_wrlock(a)
Definition: lock.h:236
#define ast_rwlock_rdlock(a)
Definition: lock.h:235
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition: lock.h:224
#define ast_rwlock_destroy(rwlock)
Definition: lock.h:233
#define ast_rwlock_unlock(a)
Definition: lock.h:234
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
Asterisk module definitions.
Core PBX routines and definitions.
static int refer_data_cmp_fn(void *obj, void *arg, int flags)
Definition: refer.c:82
void ast_refer_var_unref_current(struct ast_refer_var_iterator *iter)
Unref a refer var from inside an iterator loop.
Definition: refer.c:370
int ast_refer_tech_unregister(const struct ast_refer_tech *tech)
Unregister a refer technology.
Definition: refer.c:490
const char * ast_refer_get_to(const struct ast_refer *refer)
Retrieve the destination of this refer.
Definition: refer.c:229
int ast_refer_var_iterator_next(struct ast_refer_var_iterator *iter, const char **name, const char **value)
Get the next variable name and value.
Definition: refer.c:349
static void refer_shutdown(void)
Definition: refer.c:513
static int refer_set_var_full(struct ast_refer *refer, const char *name, const char *value)
Definition: refer.c:282
size_t current
Definition: refer.c:80
struct ast_refer_var_iterator * ast_refer_var_iterator_init(const struct ast_refer *refer)
Create a new refer variable iterator.
Definition: refer.c:335
struct ast_refer * ast_refer_alloc(void)
Allocate a refer.
Definition: refer.c:122
const char * ast_refer_get_from(const struct ast_refer *refer)
Retrieve the source of this refer.
Definition: refer.c:224
static int refer_tech_cmp(const struct ast_refer_tech *vec_elem, const struct ast_refer_tech *srch)
Comparison callback for ast_refer_tech vector removal.
Definition: refer.c:482
struct @381 refer_techs
Vector of refer technologies.
const char * ast_refer_get_var(struct ast_refer *refer, const char *name)
Get the specified variable on the refer.
Definition: refer.c:315
static ast_rwlock_t refer_techs_lock
Lock for refer_techs vector.
Definition: refer.c:77
int ast_refer_set_var_outbound(struct ast_refer *refer, const char *name, const char *value)
Set a variable on the refer being sent to a refer tech directly.
Definition: refer.c:310
const char * ast_refer_get_endpoint(const struct ast_refer *refer)
Retrieve the endpoint associated with this refer.
Definition: refer.c:244
char * ast_refer_get_var_and_unlink(struct ast_refer *refer, const char *name)
Get the specified variable on the refer and unlink it from the container of variables.
Definition: refer.c:267
int ast_refer_set_endpoint(struct ast_refer *refer, const char *fmt,...)
Set the technology's endpoint associated with this refer.
Definition: refer.c:208
static void refer_destructor(void *obj)
Definition: refer.c:114
int ast_refer_set_from(struct ast_refer *refer, const char *fmt,...)
Set the 'from' URI of a refer.
Definition: refer.c:169
struct ast_refer * ast_refer_destroy(struct ast_refer *refer)
Destroy an ast_refer.
Definition: refer.c:152
int ast_refer_set_refer_to(struct ast_refer *refer, const char *fmt,...)
Set the 'refer_to' URI of a refer.
Definition: refer.c:180
const char * ast_refer_get_refer_to(const struct ast_refer *refer)
Get the "refer-to" value of a refer.
Definition: refer.c:219
int ast_refer_set_tech(struct ast_refer *refer, const char *fmt,...)
Set the technology associated with this refer.
Definition: refer.c:197
static void refer_data_destructor(void *obj)
Definition: refer.c:108
int ast_refer_tech_register(const struct ast_refer_tech *tech)
Register a refer technology.
Definition: refer.c:446
int ast_refer_set_to_self(struct ast_refer *refer, int val)
Set the 'to_self' value of a refer.
Definition: refer.c:191
int ast_refer_send(struct ast_refer *refer)
Send a refer directly to an endpoint.
Definition: refer.c:411
static struct refer_data * refer_data_find(struct ao2_container *vars, const char *name)
Definition: refer.c:262
struct ast_refer * ast_refer_ref(struct ast_refer *refer)
Bump a refer's ref count.
Definition: refer.c:146
int ast_refer_set_to(struct ast_refer *refer, const char *fmt,...)
Set the 'to' URI of a refer.
Definition: refer.c:158
int ast_refer_init(void)
Definition: refer.c:529
int ast_refer_get_to_self(const struct ast_refer *refer)
Retrieve the "to_self" value of this refer.
Definition: refer.c:234
void ast_refer_var_iterator_destroy(struct ast_refer_var_iterator *iter)
Destroy a refer variable iterator.
Definition: refer.c:376
static const struct ast_refer_tech * refer_find_by_tech_name(const char *tech_name)
Definition: refer.c:396
const char * ast_refer_get_tech(const struct ast_refer *refer)
Retrieve the technology associated with this refer.
Definition: refer.c:239
static struct refer_data * refer_data_new(const char *name)
Definition: refer.c:249
Out-of-call refer support.
static const struct ast_refer_tech refer_tech
#define NULL
Definition: resample.c:96
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_build_va(x, field, fmt, args)
Set a field to a complex (built) value.
Definition: stringfields.h:591
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
A refer technology.
Definition: refer.h:52
int(*const refer_send)(const struct ast_refer *refer)
Send a refer.
Definition: refer.h:73
const char *const name
Name of this refer technology.
Definition: refer.h:61
struct ao2_iterator iter
Definition: refer.c:331
struct refer_data * current_used
Definition: refer.c:332
A refer.
Definition: refer.c:57
struct ao2_container * vars
Definition: refer.c:73
int to_self
Definition: refer.c:71
const ast_string_field tech
Definition: refer.c:69
const ast_string_field from
Definition: refer.c:69
const ast_string_field refer_to
Definition: refer.c:69
const ast_string_field endpoint
Definition: refer.c:69
const ast_string_field to
Definition: refer.c:69
Structure for rwlock and tracking information.
Definition: lock.h:157
char * value
Definition: refer.c:49
char * name
Definition: refer.c:47
char stuff[0]
Definition: refer.c:51
struct ast_refer * refer
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
An API for managing task processing threads that can be shared across modules.
Vector container support.
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition: vector.h:571
#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_REMOVE_CMP_UNORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison.
Definition: vector.h:488
#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(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680