Asterisk - The Open Source Telephony Project GIT-master-5782b03
stasis_channels.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Matt Jordan <mjordan@digium.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 Stasis Messages and Data Types for Channel Objects
22 *
23 * \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
24 *
25 */
26
27/*** MODULEINFO
28 <support_level>core</support_level>
29 ***/
30
31#include "asterisk.h"
32
33#include "asterisk/astobj2.h"
34#include "asterisk/json.h"
35#include "asterisk/pbx.h"
36#include "asterisk/bridge.h"
37#include "asterisk/translate.h"
38#include "asterisk/stasis.h"
40#include "asterisk/dial.h"
42#include "asterisk/utf8.h"
43
44/*** DOCUMENTATION
45 <managerEvent language="en_US" name="VarSet">
46 <managerEventInstance class="EVENT_FLAG_DIALPLAN">
47 <synopsis>Raised when a variable is set to a particular value.</synopsis>
48 <syntax>
49 <channel_snapshot/>
50 <parameter name="Variable">
51 <para>The variable being set.</para>
52 </parameter>
53 <parameter name="Value">
54 <para>The new value of the variable.</para>
55 </parameter>
56 </syntax>
57 </managerEventInstance>
58 </managerEvent>
59 <managerEvent language="en_US" name="AgentLogin">
60 <managerEventInstance class="EVENT_FLAG_AGENT">
61 <synopsis>Raised when an Agent has logged in.</synopsis>
62 <syntax>
63 <channel_snapshot/>
64 <parameter name="Agent">
65 <para>Agent ID of the agent.</para>
66 </parameter>
67 </syntax>
68 <see-also>
69 <ref type="application">AgentLogin</ref>
70 <ref type="managerEvent">AgentLogoff</ref>
71 </see-also>
72 </managerEventInstance>
73 </managerEvent>
74 <managerEvent language="en_US" name="AgentLogoff">
75 <managerEventInstance class="EVENT_FLAG_AGENT">
76 <synopsis>Raised when an Agent has logged off.</synopsis>
77 <syntax>
78 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentLogin']/managerEventInstance/syntax/parameter)" />
79 <parameter name="Logintime">
80 <para>The number of seconds the agent was logged in.</para>
81 </parameter>
82 </syntax>
83 <see-also>
84 <ref type="managerEvent">AgentLogin</ref>
85 </see-also>
86 </managerEventInstance>
87 </managerEvent>
88 <managerEvent language="en_US" name="ChannelTalkingStart">
89 <managerEventInstance class="EVENT_FLAG_CLASS">
90 <synopsis>Raised when talking is detected on a channel.</synopsis>
91 <syntax>
92 <channel_snapshot/>
93 </syntax>
94 <see-also>
95 <ref type="function">TALK_DETECT</ref>
96 <ref type="managerEvent">ChannelTalkingStop</ref>
97 </see-also>
98 </managerEventInstance>
99 </managerEvent>
100 <managerEvent language="en_US" name="ChannelTalkingStop">
101 <managerEventInstance class="EVENT_FLAG_CLASS">
102 <synopsis>Raised when talking is no longer detected on a channel.</synopsis>
103 <syntax>
104 <channel_snapshot/>
105 <parameter name="Duration">
106 <para>The length in time, in milliseconds, that talking was
107 detected on the channel.</para>
108 </parameter>
109 </syntax>
110 <see-also>
111 <ref type="function">TALK_DETECT</ref>
112 <ref type="managerEvent">ChannelTalkingStart</ref>
113 </see-also>
114 </managerEventInstance>
115 </managerEvent>
116***/
117
118#define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7
119
123
125{
126 return ao2_bump(channel_cache);
127}
128
130{
131 return channel_topic_all;
132}
133
135{
137}
138
139/*!
140 * \internal
141 * \brief Hash function for \ref ast_channel_snapshot objects
142 */
143static int channel_snapshot_hash_cb(const void *obj, const int flags)
144{
145 const struct ast_channel_snapshot *object = obj;
146 const char *key;
147
148 switch (flags & OBJ_SEARCH_MASK) {
149 case OBJ_SEARCH_KEY:
150 key = obj;
151 break;
153 key = object->base->name;
154 break;
155 default:
156 ast_assert(0);
157 return 0;
158 }
159 return ast_str_case_hash(key);
160}
161
162/*!
163 * \internal
164 * \brief Comparison function for \ref ast_channel_snapshot objects
165 */
166static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
167{
168 const struct ast_channel_snapshot *object_left = obj;
169 const struct ast_channel_snapshot *object_right = arg;
170 const char *right_key = arg;
171 int cmp;
172
173 switch (flags & OBJ_SEARCH_MASK) {
175 right_key = object_right->base->name;
176 case OBJ_SEARCH_KEY:
177 cmp = strcasecmp(object_left->base->name, right_key);
178 break;
180 cmp = strncasecmp(object_left->base->name, right_key, strlen(right_key));
181 break;
182 default:
183 cmp = 0;
184 break;
185 }
186 if (cmp) {
187 return 0;
188 }
189 return CMP_MATCH;
190}
191
192/*!
193 * \internal
194 * \brief Hash function (using uniqueid) for \ref ast_channel_snapshot objects
195 */
196static int channel_snapshot_uniqueid_hash_cb(const void *obj, const int flags)
197{
198 const struct ast_channel_snapshot *object = obj;
199 const char *key;
200
201 switch (flags & OBJ_SEARCH_MASK) {
202 case OBJ_SEARCH_KEY:
203 key = obj;
204 break;
206 key = object->base->uniqueid;
207 break;
208 default:
209 ast_assert(0);
210 return 0;
211 }
212 return ast_str_case_hash(key);
213}
214
215/*!
216 * \internal
217 * \brief Comparison function (using uniqueid) for \ref ast_channel_snapshot objects
218 */
219static int channel_snapshot_uniqueid_cmp_cb(void *obj, void *arg, int flags)
220{
221 const struct ast_channel_snapshot *object_left = obj;
222 const struct ast_channel_snapshot *object_right = arg;
223 const char *right_key = arg;
224 int cmp;
225
226 switch (flags & OBJ_SEARCH_MASK) {
228 right_key = object_right->base->uniqueid;
229 case OBJ_SEARCH_KEY:
230 cmp = strcasecmp(object_left->base->uniqueid, right_key);
231 break;
233 cmp = strncasecmp(object_left->base->uniqueid, right_key, strlen(right_key));
234 break;
235 default:
236 cmp = 0;
237 break;
238 }
239 if (cmp) {
240 return 0;
241 }
242 return CMP_MATCH;
243}
244
245static void channel_snapshot_dtor(void *obj)
246{
247 struct ast_channel_snapshot *snapshot = obj;
248
249 ao2_cleanup(snapshot->base);
250 ao2_cleanup(snapshot->peer);
251 ao2_cleanup(snapshot->caller);
252 ao2_cleanup(snapshot->connected);
253 ao2_cleanup(snapshot->bridge);
254 ao2_cleanup(snapshot->dialplan);
255 ao2_cleanup(snapshot->hangup);
256 ao2_cleanup(snapshot->manager_vars);
257 ao2_cleanup(snapshot->ari_vars);
258}
259
260static void channel_snapshot_base_dtor(void *obj)
261{
262 struct ast_channel_snapshot_base *snapshot = obj;
263
265}
266
268{
269 struct ast_channel_snapshot_base *snapshot;
270
271 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_base_dtor,
273 if (!snapshot) {
274 return NULL;
275 }
276
277 if (ast_string_field_init(snapshot, 256) || ast_string_field_init_extended(snapshot, protocol_id)) {
278 ao2_ref(snapshot, -1);
279 return NULL;
280 }
281
289
290 snapshot->creationtime = ast_channel_creationtime(chan);
292
293 if (ast_channel_tech(chan)->get_pvt_uniqueid) {
294 ast_string_field_set(snapshot, protocol_id, ast_channel_tech(chan)->get_pvt_uniqueid(chan));
295 }
296
297 return snapshot;
298}
299
301{
302 const char *linkedid = S_OR(ast_channel_linkedid(chan), "");
303 const char *peeraccount = S_OR(ast_channel_peeraccount(chan), "");
304 size_t linkedid_len = strlen(linkedid) + 1;
305 size_t peeraccount_len = strlen(peeraccount) + 1;
306 struct ast_channel_snapshot_peer *snapshot;
307
308 snapshot = ao2_alloc_options(sizeof(*snapshot) + linkedid_len + peeraccount_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
309 if (!snapshot) {
310 return NULL;
311 }
312
313 strcpy(snapshot->account, peeraccount); /* Safe */
314 snapshot->linkedid = snapshot->account + peeraccount_len;
315 ast_copy_string(snapshot->linkedid, linkedid, linkedid_len); /* Safe */
316
317 return snapshot;
318}
319
320static void channel_snapshot_caller_dtor(void *obj)
321{
322 struct ast_channel_snapshot_caller *snapshot = obj;
323
325}
326
328{
329 struct ast_channel_snapshot_caller *snapshot;
330
331 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_caller_dtor,
333 if (!snapshot) {
334 return NULL;
335 }
336
337 if (ast_string_field_init(snapshot, 256)) {
338 ao2_ref(snapshot, -1);
339 return NULL;
340 }
341
342 ast_string_field_set(snapshot, name,
343 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
345 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
347 S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, ""));
348 ast_string_field_set(snapshot, ani,
349 S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
350
351 ast_string_field_set(snapshot, rdnis,
352 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
353
354 ast_string_field_set(snapshot, dnid,
355 S_OR(ast_channel_dialed(chan)->number.str, ""));
357 S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
358
359 snapshot->pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
360
361 return snapshot;
362}
363
365{
366 const char *name = S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "");
367 const char *number = S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "");
368 size_t name_len = strlen(name) + 1;
369 size_t number_len = strlen(number) + 1;
370 struct ast_channel_snapshot_connected *snapshot;
371
372 snapshot = ao2_alloc_options(sizeof(*snapshot) + name_len + number_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
373 if (!snapshot) {
374 return NULL;
375 }
376
377 strcpy(snapshot->name, name); /* Safe */
378 snapshot->number = snapshot->name + name_len;
379 ast_copy_string(snapshot->number, number, number_len); /* Safe */
380
381 return snapshot;
382}
383
385{
386 const char *uniqueid = "";
387 struct ast_bridge *bridge;
388 struct ast_channel_snapshot_bridge *snapshot;
389
390 bridge = ast_channel_get_bridge(chan);
391 if (bridge && !ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
392 uniqueid = bridge->uniqueid;
393 }
394 ao2_cleanup(bridge);
395
396 snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(uniqueid) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
397 if (!snapshot) {
398 return NULL;
399 }
400
401 strcpy(snapshot->id, uniqueid); /* Safe */
402
403 return snapshot;
404}
405
406static void channel_snapshot_dialplan_dtor(void *obj)
407{
408 struct ast_channel_snapshot_dialplan *snapshot = obj;
409
411}
412
414{
415 struct ast_channel_snapshot_dialplan *snapshot;
416
417 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dialplan_dtor,
419 if (!snapshot) {
420 return NULL;
421 }
422
423 if (ast_string_field_init(snapshot, 256)) {
424 ao2_ref(snapshot, -1);
425 return NULL;
426 }
427
428 if (ast_channel_appl(chan)) {
430 }
431 if (ast_channel_data(chan)) {
433 }
436 snapshot->priority = ast_channel_priority(chan);
437
438 return snapshot;
439}
440
442{
443 const char *hangupsource = S_OR(ast_channel_hangupsource(chan), "");
444 struct ast_channel_snapshot_hangup *snapshot;
445
446 snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(hangupsource) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
447 if (!snapshot) {
448 return NULL;
449 }
450
451 snapshot->cause = ast_channel_hangupcause(chan);
452 strcpy(snapshot->source, hangupsource); /* Safe */
453
454 return snapshot;
455}
456
458{
459 struct ast_channel_snapshot *old_snapshot;
460 struct ast_channel_snapshot *snapshot;
461
462 /* no snapshots for dummy channels */
463 if (!ast_channel_tech(chan)) {
464 return NULL;
465 }
466
467 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dtor,
469 if (!snapshot) {
470 return NULL;
471 }
472
473 old_snapshot = ast_channel_snapshot(chan);
474
475 /* Channels automatically have all segments invalidated on them initially so a check for an old
476 * snapshot existing before usage is not done here, as it can not happen. If the stored snapshot
477 * on the channel is updated as a result of this then all segments marked as invalidated will be
478 * cleared.
479 */
481 /* The base information has changed so update our snapshot */
482 snapshot->base = channel_snapshot_base_create(chan);
483 if (!snapshot->base) {
484 ao2_ref(snapshot, -1);
485 return NULL;
486 }
487 } else {
488 snapshot->base = ao2_bump(old_snapshot->base);
489 }
490
492 /* The peer information has changed so update our snapshot */
493 snapshot->peer = channel_snapshot_peer_create(chan);
494 if (!snapshot->peer) {
495 ao2_ref(snapshot, -1);
496 return NULL;
497 }
498 } else {
499 snapshot->peer = ao2_bump(old_snapshot->peer);
500 }
501
502 /* Unfortunately both caller and connected information do not have an enforced contract with
503 * the channel API. This has allowed consumers to directly get the caller or connected structure
504 * and manipulate it. Until such time as there is an enforced contract (which is being tracked under
505 * ASTERISK-28164) they are each regenerated every time a channel snapshot is created.
506 */
507 snapshot->caller = channel_snapshot_caller_create(chan);
508 if (!snapshot->caller) {
509 ao2_ref(snapshot, -1);
510 return NULL;
511 }
512
514 if (!snapshot->connected) {
515 ao2_ref(snapshot, -1);
516 return NULL;
517 }
518
520 /* The bridge has changed so update our snapshot */
521 snapshot->bridge = channel_snapshot_bridge_create(chan);
522 if (!snapshot->bridge) {
523 ao2_ref(snapshot, -1);
524 return NULL;
525 }
526 } else {
527 snapshot->bridge = ao2_bump(old_snapshot->bridge);
528 }
529
531 /* The dialplan information has changed so update our snapshot */
533 if (!snapshot->dialplan) {
534 ao2_ref(snapshot, -1);
535 return NULL;
536 }
537 } else {
538 snapshot->dialplan = ao2_bump(old_snapshot->dialplan);
539 }
540
542 /* The hangup information has changed so update our snapshot */
543 snapshot->hangup = channel_snapshot_hangup_create(chan);
544 if (!snapshot->hangup) {
545 ao2_ref(snapshot, -1);
546 return NULL;
547 }
548 } else {
549 snapshot->hangup = ao2_bump(old_snapshot->hangup);
550 }
551
552 snapshot->state = ast_channel_state(chan);
553 snapshot->amaflags = ast_channel_amaflags(chan);
554 ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
556
557 /* These have to be recreated as they may have changed, unfortunately */
559 snapshot->ari_vars = ast_channel_get_ari_vars(chan);
560
561 return snapshot;
562}
563
564static void channel_snapshot_update_dtor(void *obj)
565{
567
568 ao2_cleanup(update->old_snapshot);
569 ao2_cleanup(update->new_snapshot);
570}
571
573{
575
578 if (!update) {
579 return NULL;
580 }
581
582 update->old_snapshot = ao2_bump(ast_channel_snapshot(chan));
583 update->new_snapshot = ast_channel_snapshot_create(chan);
584 if (!update->new_snapshot) {
585 ao2_ref(update, -1);
586 return NULL;
587 }
588
589 return update;
590}
591
593{
594 if (chan) {
596 } else {
598 }
599}
600
601static void channel_blob_dtor(void *obj)
602{
603 struct ast_channel_blob *event = obj;
604 ao2_cleanup(event->snapshot);
605 ast_json_unref(event->blob);
606}
607
609 struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring,
610 const char *dialstatus, const char *forward)
611{
612 struct ast_multi_channel_blob *payload;
613 struct stasis_message *msg;
614 struct ast_json *blob;
615 struct ast_channel_snapshot *peer_snapshot;
616
617 if (!ast_channel_dial_type()) {
618 return;
619 }
620
621 ast_assert(peer != NULL);
622
623 blob = ast_json_pack("{s: s, s: s, s: s}",
624 "dialstatus", S_OR(dialstatus, ""),
625 "forward", S_OR(forward, ""),
626 "dialstring", S_OR(dialstring, ""));
627 if (!blob) {
628 return;
629 }
630 payload = ast_multi_channel_blob_create(blob);
631 ast_json_unref(blob);
632 if (!payload) {
633 return;
634 }
635
636 if (caller) {
637 struct ast_channel_snapshot *caller_snapshot;
638
640 if (ast_strlen_zero(dialstatus)) {
642 } else {
643 caller_snapshot = ast_channel_snapshot_create(caller);
644 }
646 if (!caller_snapshot) {
647 ao2_ref(payload, -1);
648 return;
649 }
650 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
651 ao2_ref(caller_snapshot, -1);
652 }
653
655 if (ast_strlen_zero(dialstatus)) {
657 } else {
658 peer_snapshot = ast_channel_snapshot_create(peer);
659 }
661 if (!peer_snapshot) {
662 ao2_ref(payload, -1);
663 return;
664 }
665 ast_multi_channel_blob_add_channel(payload, "peer", peer_snapshot);
666 ao2_ref(peer_snapshot, -1);
667
668 if (forwarded) {
669 struct ast_channel_snapshot *forwarded_snapshot;
670
671 ast_channel_lock(forwarded);
672 forwarded_snapshot = ast_channel_snapshot_create(forwarded);
673 ast_channel_unlock(forwarded);
674 if (!forwarded_snapshot) {
675 ao2_ref(payload, -1);
676 return;
677 }
678 ast_multi_channel_blob_add_channel(payload, "forwarded", forwarded_snapshot);
679 ao2_ref(forwarded_snapshot, -1);
680 }
681
683 ao2_ref(payload, -1);
684 if (msg) {
686 ao2_ref(msg, -1);
687 }
688}
689
690static void remove_dial_masquerade(struct ast_channel *peer);
692static int set_dial_masquerade(struct ast_channel *caller,
693 struct ast_channel *peer, const char *dialstring);
694
696 struct ast_channel *forwarded, const char *dialstring, const char *dialstatus,
697 const char *forward)
698{
699 ast_assert(peer != NULL);
700
701 /* XXX With an early bridge the below dial masquerade datastore code could, theoretically,
702 * go away as the act of changing the channel during dialing would be done using the bridge
703 * API itself and not a masquerade.
704 */
705
706 if (caller) {
707 /*
708 * Lock two or three channels.
709 *
710 * We need to hold the locks to hold off a potential masquerade
711 * messing up the stasis dial event ordering.
712 */
713 for (;; ast_channel_unlock(caller), sched_yield()) {
716 continue;
717 }
718 if (forwarded && ast_channel_trylock(forwarded)) {
720 continue;
721 }
722 break;
723 }
724
725 if (ast_strlen_zero(dialstatus)) {
726 set_dial_masquerade(caller, peer, dialstring);
727 } else {
729 }
730 }
731
732 ast_channel_publish_dial_internal(caller, peer, forwarded, dialstring, dialstatus,
733 forward);
734
735 if (caller) {
736 if (forwarded) {
737 ast_channel_unlock(forwarded);
738 }
742 }
743}
744
746 const char *dialstring, const char *dialstatus)
747{
748 ast_channel_publish_dial_forward(caller, peer, NULL, dialstring, dialstatus, NULL);
749}
750
753 struct ast_json *blob)
754{
755 struct stasis_message *msg;
756 struct ast_channel_blob *obj;
757
758 obj = ao2_alloc(sizeof(*obj), channel_blob_dtor);
759 if (!obj) {
760 return NULL;
761 }
762
763 if (snapshot) {
764 obj->snapshot = snapshot;
765 ao2_ref(obj->snapshot, +1);
766 }
767 if (!blob) {
769 }
770 obj->blob = ast_json_ref(blob);
771
772 msg = stasis_message_create(type, obj);
773 ao2_cleanup(obj);
774 return msg;
775}
776
779 struct ast_json *blob)
780{
781 struct ast_channel_snapshot *snapshot;
782 struct stasis_message *msg;
783
784 if (!type) {
785 return NULL;
786 }
787
788 snapshot = ast_channel_snapshot_get_latest(channel_id);
789 msg = create_channel_blob_message(snapshot, type, blob);
790 ao2_cleanup(snapshot);
791 return msg;
792}
793
795 struct stasis_message_type *type, struct ast_json *blob)
796{
797 struct ast_channel_snapshot *snapshot;
798 struct stasis_message *msg;
799
800 if (!type) {
801 return NULL;
802 }
803
804 snapshot = chan ? ao2_bump(ast_channel_snapshot(chan)) : NULL;
805 msg = create_channel_blob_message(snapshot, type, blob);
806 ao2_cleanup(snapshot);
807 return msg;
808}
809
810/*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */
812 struct ast_channel_snapshot *snapshot; /*!< A channel snapshot */
813 char role[0]; /*!< The role assigned to the channel */
814};
815
816/*! \brief A multi channel blob data structure for multi_channel_blob stasis messages */
818 struct ao2_container *channel_snapshots; /*!< A container holding the snapshots */
819 struct ast_json *blob; /*!< A blob of JSON data */
820};
821
822/*!
823 * \internal
824 * \brief Comparison function for \ref channel_role_snapshot objects
825 */
826static int channel_role_cmp_cb(void *obj, void *arg, int flags)
827{
828 const struct channel_role_snapshot *object_left = obj;
829 const struct channel_role_snapshot *object_right = arg;
830 const char *right_key = arg;
831 int cmp;
832
833 switch (flags & OBJ_SEARCH_MASK) {
835 right_key = object_right->role;
836 case OBJ_SEARCH_KEY:
837 cmp = strcasecmp(object_left->role, right_key);
838 break;
840 cmp = strncasecmp(object_left->role, right_key, strlen(right_key));
841 break;
842 default:
843 cmp = 0;
844 break;
845 }
846 if (cmp) {
847 return 0;
848 }
849 return CMP_MATCH;
850}
851
852/*!
853 * \internal
854 * \brief Hash function for \ref channel_role_snapshot objects
855 */
856static int channel_role_hash_cb(const void *obj, const int flags)
857{
858 const struct channel_role_snapshot *object = obj;
859 const char *key;
860
861 switch (flags & OBJ_SEARCH_MASK) {
862 case OBJ_SEARCH_KEY:
863 key = obj;
864 break;
866 key = object->role;
867 break;
868 default:
869 ast_assert(0);
870 return 0;
871 }
872 return ast_str_case_hash(key);
873}
874
875/*!
876 * \internal
877 * \brief Destructor for \ref ast_multi_channel_blob objects
878 */
879static void multi_channel_blob_dtor(void *obj)
880{
881 struct ast_multi_channel_blob *multi_blob = obj;
882
883 ao2_cleanup(multi_blob->channel_snapshots);
884 ast_json_unref(multi_blob->blob);
885}
886
888{
889 struct ast_multi_channel_blob *obj;
890
891 ast_assert(blob != NULL);
892
893 obj = ao2_alloc(sizeof(*obj), multi_channel_blob_dtor);
894 if (!obj) {
895 return NULL;
896 }
897
900 if (!obj->channel_snapshots) {
901 ao2_ref(obj, -1);
902 return NULL;
903 }
904
905 obj->blob = ast_json_ref(blob);
906 return obj;
907}
908
910{
911 ast_assert(!ast_strlen_zero(uniqueid));
912
913 return ao2_find(channel_cache, uniqueid, OBJ_SEARCH_KEY);
914}
915
917{
919
921}
922
924{
926 struct stasis_message *message;
927
929 return;
930 }
931
933 if (!update) {
934 return;
935 }
936
938 /* In the success path message holds a reference to update so it will be valid
939 * for the lifetime of this function until the end.
940 */
941 ao2_ref(update, -1);
942 if (!message) {
943 return;
944 }
945
948
950
952 ao2_ref(message, -1);
953}
954
955static void channel_role_snapshot_dtor(void *obj)
956{
957 struct channel_role_snapshot *role_snapshot = obj;
958
959 ao2_cleanup(role_snapshot->snapshot);
960}
961
963{
964 struct channel_role_snapshot *role_snapshot;
965 int role_len = strlen(role) + 1;
966
967 if (!obj || ast_strlen_zero(role) || !snapshot) {
968 return;
969 }
970
971 role_snapshot = ao2_alloc_options(sizeof(*role_snapshot) + role_len,
973 if (!role_snapshot) {
974 return;
975 }
976 ast_copy_string(role_snapshot->role, role, role_len);
977 role_snapshot->snapshot = snapshot;
978 ao2_ref(role_snapshot->snapshot, +1);
979 ao2_link(obj->channel_snapshots, role_snapshot);
980 ao2_ref(role_snapshot, -1);
981}
982
984{
985 struct channel_role_snapshot *role_snapshot;
986 struct ast_channel_snapshot *snapshot;
987
988 if (!obj || ast_strlen_zero(role)) {
989 return NULL;
990 }
991 role_snapshot = ao2_find(obj->channel_snapshots, role, OBJ_SEARCH_KEY);
992 /* Note that this function does not increase the ref count on snapshot */
993 if (!role_snapshot) {
994 return NULL;
995 }
996 snapshot = role_snapshot->snapshot;
997 ao2_ref(role_snapshot, -1);
998 return snapshot;
999}
1000
1002{
1003 struct ao2_container *ret_container;
1004 struct ao2_iterator *it_role_snapshots;
1005 struct channel_role_snapshot *role_snapshot;
1006 char *arg;
1007
1008 if (!obj || ast_strlen_zero(role)) {
1009 return NULL;
1010 }
1011
1015 if (!ret_container) {
1016 return NULL;
1017 }
1018
1019 arg = ast_strdupa(role);
1020 it_role_snapshots = ao2_callback(obj->channel_snapshots,
1022 if (!it_role_snapshots) {
1023 ao2_ref(ret_container, -1);
1024 return NULL;
1025 }
1026
1027 while ((role_snapshot = ao2_iterator_next(it_role_snapshots))) {
1028 ao2_link(ret_container, role_snapshot->snapshot);
1029 ao2_ref(role_snapshot, -1);
1030 }
1031 ao2_iterator_destroy(it_role_snapshots);
1032
1033 return ret_container;
1034}
1035
1037{
1038 if (!obj) {
1039 return NULL;
1040 }
1041 return obj->blob;
1042}
1043
1045{
1047}
1048
1050{
1053}
1054
1057{
1059}
1060
1062{
1064 struct stasis_message *message;
1065
1067 return;
1068 }
1069
1071 return;
1072 }
1073
1075 if (!update) {
1076 return;
1077 }
1078
1079 /* If an old snapshot exists and is the same as this newly created one don't bother
1080 * raising a message as it hasn't changed.
1081 */
1082 if (update->old_snapshot && !memcmp(update->old_snapshot, update->new_snapshot, sizeof(struct ast_channel_snapshot))) {
1083 ao2_ref(update, -1);
1084 return;
1085 }
1086
1088 /* In the success path message holds a reference to update so it will be valid
1089 * for the lifetime of this function until the end.
1090 */
1091 ao2_ref(update, -1);
1092 if (!message) {
1093 return;
1094 }
1095
1096 /* We lock these ourselves so that the update is atomic and there isn't time where a
1097 * snapshot is not in the cache.
1098 */
1101
1104
1105 /* The same applies here. */
1108
1111
1112 ast_channel_snapshot_set(chan, update->new_snapshot);
1113
1114 /* As this is now the new snapshot any existing invalidated segments have been
1115 * created fresh and are up to date.
1116 */
1118
1121 ao2_ref(message, -1);
1122}
1123
1125{
1126 struct stasis_message *message;
1127
1128 if (!blob) {
1129 blob = ast_json_null();
1130 }
1131
1133 if (message) {
1135 ao2_ref(message, -1);
1136 }
1137}
1138
1140{
1141 struct stasis_message *message;
1142
1143 if (!blob) {
1144 blob = ast_json_null();
1145 }
1146
1147 message = ast_channel_blob_create(chan, type, blob);
1148 if (message) {
1150 ao2_ref(message, -1);
1151 }
1152}
1153
1154void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
1155{
1156 struct ast_json *blob;
1158 char *new_value = NULL;
1159 size_t new_value_size = 0;
1160
1161 ast_assert(name != NULL);
1162 ast_assert(value != NULL);
1163
1164 /*
1165 * Call with new-value == NULL to just check for invalid UTF-8
1166 * sequences and get size of buffer needed.
1167 */
1168 result = ast_utf8_replace_invalid_chars(new_value, &new_value_size,
1169 value, strlen(value));
1170
1172 /*
1173 * If there were no invalid sequences, we can use
1174 * the value directly.
1175 */
1176 new_value = (char *)value;
1177 } else {
1178 /*
1179 * If there were invalid sequences, we need to replace
1180 * them with the UTF-8 U+FFFD replacement character.
1181 */
1182 new_value = ast_alloca(new_value_size);
1183
1184 result = ast_utf8_replace_invalid_chars(new_value, &new_value_size,
1185 value, strlen(value));
1186
1187 ast_log(LOG_WARNING, "%s: The contents of variable '%s' had invalid UTF-8 sequences which were replaced",
1188 ast_channel_name(chan), name);
1189 }
1190
1191 blob = ast_json_pack("{s: s, s: s}",
1192 "variable", name,
1193 "value", new_value);
1194 if (!blob) {
1195 ast_log(LOG_ERROR, "Error creating message\n");
1196 return;
1197 }
1198
1199 /*! If there are manager variables, force a cache update */
1200 if (chan && ast_channel_has_manager_vars()) {
1202 }
1203
1204 /* This function is NULL safe for global variables */
1206 ast_json_unref(blob);
1207}
1208
1210{
1211 struct ast_str *channel_event_string;
1212 struct ast_channel_blob *obj = stasis_message_data(msg);
1213 const char *variable =
1214 ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
1215 char *value;
1216 struct ast_manager_event_blob *ev;
1217
1219 "value")));
1220 if (!value) {
1221 return NULL;
1222 }
1223
1224 if (obj->snapshot) {
1225 channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
1226 } else {
1227 channel_event_string = ast_str_create(35);
1228 ast_str_set(&channel_event_string, 0,
1229 "Channel: none\r\n"
1230 "Uniqueid: none\r\n");
1231 }
1232 if (!channel_event_string) {
1233 ast_free(value);
1234 return NULL;
1235 }
1236
1238 "%s"
1239 "Variable: %s\r\n"
1240 "Value: %s\r\n",
1241 ast_str_buffer(channel_event_string), variable, value);
1242 ast_free(channel_event_string);
1243 ast_free(value);
1244 return ev;
1245}
1246
1248{
1249 struct ast_str *channel_string;
1250 struct ast_channel_blob *obj = stasis_message_data(msg);
1251 const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
1252 struct ast_manager_event_blob *ev;
1253
1254 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1255 if (!channel_string) {
1256 return NULL;
1257 }
1258
1260 "%s"
1261 "Agent: %s\r\n",
1262 ast_str_buffer(channel_string), agent);
1263 ast_free(channel_string);
1264 return ev;
1265}
1266
1268{
1269 struct ast_str *channel_string;
1270 struct ast_channel_blob *obj = stasis_message_data(msg);
1271 const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
1272 long logintime = ast_json_integer_get(ast_json_object_get(obj->blob, "logintime"));
1273 struct ast_manager_event_blob *ev;
1274
1275 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1276 if (!channel_string) {
1277 return NULL;
1278 }
1279
1281 "%s"
1282 "Agent: %s\r\n"
1283 "Logintime: %ld\r\n",
1284 ast_str_buffer(channel_string), agent, logintime);
1285 ast_free(channel_string);
1286 return ev;
1287}
1288
1290 const struct ast_channel_snapshot *snapshot,
1291 const struct stasis_message_sanitizer *sanitize)
1292{
1293 struct ast_json *json_chan;
1294
1295 if (snapshot == NULL
1296 || (sanitize
1297 && sanitize->channel_snapshot
1298 && sanitize->channel_snapshot(snapshot))) {
1299 return NULL;
1300 }
1301
1302 json_chan = ast_json_pack(
1303 /* Broken up into groups for readability */
1304 "{ s: s, s: s, s: s, s: s,"
1305 " s: o, s: o, s: s,"
1306 " s: o, s: o, s: s }",
1307 /* First line */
1308 "id", snapshot->base->uniqueid,
1309 "name", snapshot->base->name,
1310 "state", ast_state2str(snapshot->state),
1311 "protocol_id", snapshot->base->protocol_id,
1312 /* Second line */
1313 "caller", ast_json_name_number(
1314 snapshot->caller->name, snapshot->caller->number),
1315 "connected", ast_json_name_number(
1316 snapshot->connected->name, snapshot->connected->number),
1317 "accountcode", snapshot->base->accountcode,
1318 /* Third line */
1319 "dialplan", ast_json_dialplan_cep_app(
1320 snapshot->dialplan->context, snapshot->dialplan->exten, snapshot->dialplan->priority,
1321 snapshot->dialplan->appl, snapshot->dialplan->data),
1322 "creationtime", ast_json_timeval(snapshot->base->creationtime, NULL),
1323 "language", snapshot->base->language);
1324
1325 if (!ast_strlen_zero(snapshot->caller->rdnis)) {
1326 ast_json_object_set(json_chan, "caller_rdnis", ast_json_string_create(snapshot->caller->rdnis));
1327 }
1328
1329 if (snapshot->ari_vars && !AST_LIST_EMPTY(snapshot->ari_vars)) {
1330 ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars));
1331 }
1332
1333 if (!ast_strlen_zero(snapshot->base->tenantid)) {
1334 ast_json_object_set(json_chan, "tenantid", ast_json_string_create(snapshot->base->tenantid));
1335 }
1336
1337 return json_chan;
1338}
1339
1341 const struct ast_channel_snapshot *old_snapshot,
1342 const struct ast_channel_snapshot *new_snapshot)
1343{
1344 ast_assert(old_snapshot != NULL);
1345 ast_assert(new_snapshot != NULL);
1346
1347 /* We actually get some snapshots with CEP set, but before the
1348 * application is set. Since empty application is invalid, we treat
1349 * setting the application from nothing as a CEP change.
1350 */
1351 if (ast_strlen_zero(old_snapshot->dialplan->appl) &&
1352 !ast_strlen_zero(new_snapshot->dialplan->appl)) {
1353 return 0;
1354 }
1355
1356 return old_snapshot->dialplan->priority == new_snapshot->dialplan->priority &&
1357 strcmp(old_snapshot->dialplan->context, new_snapshot->dialplan->context) == 0 &&
1358 strcmp(old_snapshot->dialplan->exten, new_snapshot->dialplan->exten) == 0;
1359}
1360
1362 const struct ast_channel_snapshot *old_snapshot,
1363 const struct ast_channel_snapshot *new_snapshot)
1364{
1365 ast_assert(old_snapshot != NULL);
1366 ast_assert(new_snapshot != NULL);
1367 return strcmp(old_snapshot->caller->number, new_snapshot->caller->number) == 0 &&
1368 strcmp(old_snapshot->caller->name, new_snapshot->caller->name) == 0;
1369}
1370
1372 const struct ast_channel_snapshot *old_snapshot,
1373 const struct ast_channel_snapshot *new_snapshot)
1374{
1375 ast_assert(old_snapshot != NULL);
1376 ast_assert(new_snapshot != NULL);
1377 return strcmp(old_snapshot->connected->number, new_snapshot->connected->number) == 0 &&
1378 strcmp(old_snapshot->connected->name, new_snapshot->connected->name) == 0;
1379}
1380
1382 struct stasis_message *message,
1383 const char *type,
1384 const struct stasis_message_sanitizer *sanitize)
1385{
1386 struct ast_json *to_json;
1387 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1388 struct ast_json *blob = channel_blob->blob;
1389 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1390 const struct timeval *tv = stasis_message_timestamp(message);
1391 int res = 0;
1392
1393 if (blob == NULL || ast_json_is_null(blob)) {
1394 to_json = ast_json_object_create();
1395 } else {
1396 /* blobs are immutable, so shallow copies are fine */
1397 to_json = ast_json_copy(blob);
1398 }
1399 if (!to_json) {
1400 return NULL;
1401 }
1402
1403 res |= ast_json_object_set(to_json, "type", ast_json_string_create(type));
1404 res |= ast_json_object_set(to_json, "timestamp",
1405 ast_json_timeval(*tv, NULL));
1406
1407 /* For global channel messages, the snapshot is optional */
1408 if (snapshot) {
1409 struct ast_json *json_channel;
1410
1411 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1412 if (!json_channel) {
1413 ast_json_unref(to_json);
1414 return NULL;
1415 }
1416
1417 res |= ast_json_object_set(to_json, "channel", json_channel);
1418 }
1419
1420 if (res != 0) {
1421 ast_json_unref(to_json);
1422 return NULL;
1423 }
1424
1425 return to_json;
1426}
1427
1429 struct stasis_message *message,
1430 const struct stasis_message_sanitizer *sanitize)
1431{
1432 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1433 struct ast_json *blob = channel_blob->blob;
1434 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1435 const char *direction =
1436 ast_json_string_get(ast_json_object_get(blob, "direction"));
1437 const char *digit =
1439 long duration_ms =
1440 ast_json_integer_get(ast_json_object_get(blob, "duration_ms"));
1441 const struct timeval *tv = stasis_message_timestamp(message);
1442 struct ast_json *json_channel;
1443
1444 /* Only present received DTMF end events as JSON */
1445 if (strcasecmp("Received", direction) != 0) {
1446 return NULL;
1447 }
1448
1449 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1450 if (!json_channel) {
1451 return NULL;
1452 }
1453
1454 return ast_json_pack("{s: s, s: o, s: s, s: I, s: o}",
1455 "type", "ChannelDtmfReceived",
1456 "timestamp", ast_json_timeval(*tv, NULL),
1457 "digit", digit,
1458 "duration_ms", (ast_json_int_t)duration_ms,
1459 "channel", json_channel);
1460}
1461
1463 struct stasis_message *message,
1464 const struct stasis_message_sanitizer *sanitize)
1465{
1466 return channel_blob_to_json(message, "ChannelVarset", sanitize);
1467}
1468
1470 struct stasis_message *message,
1471 const struct stasis_message_sanitizer *sanitize)
1472{
1473 return channel_blob_to_json(message, "ChannelHangupRequest", sanitize);
1474}
1475
1476static struct ast_json *dial_to_json(
1477 struct stasis_message *message,
1478 const struct stasis_message_sanitizer *sanitize)
1479{
1481 struct ast_json *blob = ast_multi_channel_blob_get_json(payload);
1482 const char *dialstatus =
1483 ast_json_string_get(ast_json_object_get(blob, "dialstatus"));
1484 const char *forward =
1485 ast_json_string_get(ast_json_object_get(blob, "forward"));
1486 const char *dialstring =
1487 ast_json_string_get(ast_json_object_get(blob, "dialstring"));
1488 struct ast_json *caller_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "caller"), sanitize);
1489 struct ast_json *peer_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "peer"), sanitize);
1490 struct ast_json *forwarded_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "forwarded"), sanitize);
1491 struct ast_json *json;
1492 const struct timeval *tv = stasis_message_timestamp(message);
1493 int res = 0;
1494
1495 json = ast_json_pack("{s: s, s: o, s: s, s: s, s: s}",
1496 "type", "Dial",
1497 "timestamp", ast_json_timeval(*tv, NULL),
1498 "dialstatus", dialstatus,
1499 "forward", forward,
1500 "dialstring", dialstring);
1501 if (!json) {
1502 ast_json_unref(caller_json);
1503 ast_json_unref(peer_json);
1504 ast_json_unref(forwarded_json);
1505 return NULL;
1506 }
1507
1508 if (caller_json) {
1509 res |= ast_json_object_set(json, "caller", caller_json);
1510 }
1511 if (peer_json) {
1512 res |= ast_json_object_set(json, "peer", peer_json);
1513 }
1514 if (forwarded_json) {
1515 res |= ast_json_object_set(json, "forwarded", forwarded_json);
1516 }
1517
1518 if (res) {
1519 ast_json_unref(json);
1520 return NULL;
1521 }
1522
1523 return json;
1524}
1525
1527{
1528 struct ast_str *channel_string;
1529 struct ast_channel_blob *obj = stasis_message_data(msg);
1530 struct ast_manager_event_blob *blob;
1531
1532 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1533 if (!channel_string) {
1534 return NULL;
1535 }
1536
1537 blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStart",
1538 "%s", ast_str_buffer(channel_string));
1539 ast_free(channel_string);
1540
1541 return blob;
1542}
1543
1545 const struct stasis_message_sanitizer *sanitize)
1546{
1547 return channel_blob_to_json(message, "ChannelTalkingStarted", sanitize);
1548}
1549
1551{
1552 struct ast_str *channel_string;
1553 struct ast_channel_blob *obj = stasis_message_data(msg);
1554 int duration = ast_json_integer_get(ast_json_object_get(obj->blob, "duration"));
1555 struct ast_manager_event_blob *blob;
1556
1557 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1558 if (!channel_string) {
1559 return NULL;
1560 }
1561
1562 blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStop",
1563 "%s"
1564 "Duration: %d\r\n",
1565 ast_str_buffer(channel_string),
1566 duration);
1567 ast_free(channel_string);
1568
1569 return blob;
1570}
1571
1573 const struct stasis_message_sanitizer *sanitize)
1574{
1575 return channel_blob_to_json(message, "ChannelTalkingFinished", sanitize);
1576}
1577
1579 const struct stasis_message_sanitizer *sanitize)
1580{
1581 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1582 struct ast_json *blob = channel_blob->blob;
1583 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1584 const char *musicclass = ast_json_string_get(ast_json_object_get(blob, "musicclass"));
1585 const struct timeval *tv = stasis_message_timestamp(message);
1586 struct ast_json *json_channel;
1587
1588 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1589 if (!json_channel) {
1590 return NULL;
1591 }
1592
1593 return ast_json_pack("{s: s, s: o, s: s, s: o}",
1594 "type", "ChannelHold",
1595 "timestamp", ast_json_timeval(*tv, NULL),
1596 "musicclass", S_OR(musicclass, "N/A"),
1597 "channel", json_channel);
1598}
1599
1600
1602 const struct stasis_message_sanitizer *sanitize)
1603{
1604 return channel_blob_to_json(message, "ChannelToneDetected", sanitize);
1605}
1606
1608 const struct stasis_message_sanitizer *sanitize)
1609{
1610 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1611 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1612 const struct timeval *tv = stasis_message_timestamp(message);
1613 struct ast_json *json_channel;
1614
1615 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1616 if (!json_channel) {
1617 return NULL;
1618 }
1619
1620 return ast_json_pack("{s: s, s: o, s: o}",
1621 "type", "ChannelUnhold",
1622 "timestamp", ast_json_timeval(*tv, NULL),
1623 "channel", json_channel);
1624}
1625
1626/*!
1627 * @{ \brief Define channel message types.
1628 */
1631 .to_json = dial_to_json,
1632 );
1635 .to_json = varset_to_json,
1636 );
1638 .to_json = hangup_request_to_json,
1639 );
1643 .to_json = dtmf_end_to_json,
1644 );
1646 .to_json = hold_to_json,
1647 );
1649 .to_json = unhold_to_json,
1650 );
1664 );
1667 );
1670 .to_json = talking_start_to_json,
1671 );
1674 .to_json = talking_stop_to_json,
1675 );
1677 .to_json = tone_detect_to_json,
1678 );
1679
1680/*! @} */
1681
1683{
1690
1716}
1717
1719{
1720 int res = 0;
1721
1723
1724 channel_topic_all = stasis_topic_create("channel:all");
1725 if (!channel_topic_all) {
1726 return -1;
1727 }
1728
1732 if (!channel_cache) {
1733 return -1;
1734 }
1735
1739 if (!channel_cache_by_name) {
1740 return -1;
1741 }
1742
1768
1769 return res;
1770}
1771
1772/*!
1773 * \internal
1774 * \brief A list element for the dial_masquerade_datastore -- stores data about a dialed peer
1775 */
1777 /*! Called party channel. */
1779 /*! Dialstring used to call the peer. */
1781 /*! Next entry in the list. */
1783};
1784
1785static void dial_target_free(struct dial_target *doomed)
1786{
1787 if (!doomed) {
1788 return;
1789 }
1790 ast_free(doomed->dialstring);
1791 ast_channel_cleanup(doomed->peer);
1792 ast_free(doomed);
1793}
1794
1795/*!
1796 * \internal
1797 * \brief Datastore used for advancing dial state in the case of a masquerade
1798 * against a channel in the process of dialing.
1799 */
1801 /*! Calling party channel. */
1803 /*! List of called peers. */
1805};
1806
1808{
1809 struct dial_target *cur;
1810
1811 while ((cur = AST_LIST_REMOVE_HEAD(&masq_data->dialed_peers, list))) {
1812 dial_target_free(cur);
1813 }
1814}
1815
1817{
1818 struct dial_target *cur;
1819
1820 ao2_lock(masq_data);
1821 if (masq_data->caller == chan) {
1823 } else {
1825 if (cur->peer == chan) {
1827 dial_target_free(cur);
1828 break;
1829 }
1830 }
1832 }
1833 ao2_unlock(masq_data);
1834}
1835
1836static void dial_masquerade_datastore_dtor(void *vdoomed)
1837{
1839}
1840
1842{
1843 struct dial_masquerade_datastore *masq_data;
1844
1845 masq_data = ao2_alloc(sizeof(struct dial_masquerade_datastore),
1847 if (!masq_data) {
1848 return NULL;
1849 }
1851 return masq_data;
1852}
1853
1854/*!
1855 * \internal
1856 * \brief Datastore destructor for dial_masquerade_datastore
1857 */
1859{
1860 ao2_ref(data, -1);
1861}
1862
1863/*!
1864 * \internal
1865 * \brief Datastore destructor for dial_masquerade_datastore
1866 */
1868{
1870 ao2_ref(data, -1);
1871}
1872
1873static struct ast_datastore *dial_masquerade_datastore_find(struct ast_channel *chan);
1874
1875static void dial_masquerade_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1876{
1877 struct dial_masquerade_datastore *masq_data = data;
1878 struct dial_target *cur;
1879 struct ast_datastore *datastore;
1880
1881 ao2_lock(masq_data);
1882 if (!masq_data->caller) {
1883 /* Nothing to do but remove the datastore */
1884 } else if (masq_data->caller == old_chan) {
1885 /* The caller channel is being masqueraded out. */
1886 ast_debug(1, "Caller channel %s being masqueraded out to %s (is_empty:%d)\n",
1887 ast_channel_name(new_chan), ast_channel_name(old_chan),
1888 AST_LIST_EMPTY(&masq_data->dialed_peers));
1889 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
1891 cur->dialstring, "NOANSWER", NULL);
1893 cur->dialstring, NULL, NULL);
1894 }
1896 } else {
1897 /* One of the peer channels is being masqueraded out. */
1898 AST_LIST_TRAVERSE_SAFE_BEGIN(&masq_data->dialed_peers, cur, list) {
1899 if (cur->peer == old_chan) {
1900 ast_debug(1, "Peer channel %s being masqueraded out to %s\n",
1901 ast_channel_name(new_chan), ast_channel_name(old_chan));
1902 ast_channel_publish_dial_internal(masq_data->caller, new_chan, NULL,
1903 cur->dialstring, "CANCEL", NULL);
1904 ast_channel_publish_dial_internal(masq_data->caller, old_chan, NULL,
1905 cur->dialstring, NULL, NULL);
1906
1908 dial_target_free(cur);
1909 break;
1910 }
1911 }
1913 }
1914 ao2_unlock(masq_data);
1915
1916 /* Remove the datastore from the channel. */
1917 datastore = dial_masquerade_datastore_find(old_chan);
1918 if (!datastore) {
1919 return;
1920 }
1921 ast_channel_datastore_remove(old_chan, datastore);
1922 ast_datastore_free(datastore);
1923}
1924
1925/*!
1926 * \internal
1927 * \brief Primary purpose for dial_masquerade_datastore, publishes
1928 * the channel dial event needed to set the incoming channel into the
1929 * dial state during a masquerade.
1930 * \param data pointer to the dial_masquerade_datastore
1931 * \param old_chan Channel being replaced
1932 * \param new_chan Channel being pushed to dial mode
1933 */
1934static void dial_masquerade_breakdown(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1935{
1936 struct dial_masquerade_datastore *masq_data = data;
1937 struct dial_target *cur;
1938
1939 ao2_lock(masq_data);
1940
1941 if (!masq_data->caller) {
1942 ao2_unlock(masq_data);
1943 return;
1944 }
1945
1946 if (masq_data->caller == new_chan) {
1947 /*
1948 * The caller channel is being masqueraded into.
1949 * The masquerade is likely because of a blonde transfer.
1950 */
1951 ast_debug(1, "Caller channel %s being masqueraded into by %s (is_empty:%d)\n",
1952 ast_channel_name(old_chan), ast_channel_name(new_chan),
1953 AST_LIST_EMPTY(&masq_data->dialed_peers));
1954 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
1956 cur->dialstring, "NOANSWER", NULL);
1958 cur->dialstring, NULL, NULL);
1959 }
1960
1961 ao2_unlock(masq_data);
1962 return;
1963 }
1964
1965 /*
1966 * One of the peer channels is being masqueraded into.
1967 * The masquerade is likely because of a call pickup.
1968 */
1969 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
1970 if (cur->peer == new_chan) {
1971 ast_debug(1, "Peer channel %s being masqueraded into by %s\n",
1972 ast_channel_name(old_chan), ast_channel_name(new_chan));
1973 ast_channel_publish_dial_internal(masq_data->caller, old_chan, NULL,
1974 cur->dialstring, "CANCEL", NULL);
1975 ast_channel_publish_dial_internal(masq_data->caller, new_chan, NULL,
1976 cur->dialstring, NULL, NULL);
1977 break;
1978 }
1979 }
1980
1981 ao2_unlock(masq_data);
1982}
1983
1985 .type = "stasis-chan-dial-masq",
1987 .chan_fixup = dial_masquerade_fixup,
1988 .chan_breakdown = dial_masquerade_breakdown,
1989};
1990
1992 .type = "stasis-chan-dial-masq",
1994 .chan_fixup = dial_masquerade_fixup,
1995 .chan_breakdown = dial_masquerade_breakdown,
1996};
1997
1998/*!
1999 * \internal
2000 * \brief Find the dial masquerade datastore on the given channel.
2001 *
2002 * \param chan Channel a datastore data is wanted from
2003 *
2004 * \return A pointer to the datastore if it exists.
2005 */
2007{
2008 struct ast_datastore *datastore;
2009
2011 if (!datastore) {
2013 }
2014
2015 return datastore;
2016}
2017
2018/*!
2019 * \internal
2020 * \brief Add the dial masquerade datastore to a channel.
2021 *
2022 * \param chan Channel to setup dial masquerade datastore on.
2023 * \param masq_data NULL to setup caller datastore otherwise steals the ref on success.
2024 *
2025 * \retval masq_data given or created on success.
2026 * (A ref is not returned but can be obtained before chan is unlocked.)
2027 * \retval NULL on error. masq_data ref is not stolen.
2028 */
2030 struct ast_channel *chan, struct dial_masquerade_datastore *masq_data)
2031{
2032 struct ast_datastore *datastore;
2033
2035 if (!datastore) {
2036 return NULL;
2037 }
2038
2039 if (!masq_data) {
2040 masq_data = dial_masquerade_datastore_alloc();
2041 if (!masq_data) {
2042 ast_datastore_free(datastore);
2043 return NULL;
2044 }
2045 masq_data->caller = chan;
2046 }
2047
2048 datastore->data = masq_data;
2049 ast_channel_datastore_add(chan, datastore);
2050
2051 return masq_data;
2052}
2053
2054static int set_dial_masquerade(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring)
2055{
2056 struct ast_datastore *datastore;
2057 struct dial_masquerade_datastore *masq_data;
2058 struct dial_target *target;
2059
2060 /* Find or create caller datastore */
2061 datastore = dial_masquerade_datastore_find(caller);
2062 if (!datastore) {
2063 masq_data = dial_masquerade_datastore_add(caller, NULL);
2064 } else {
2065 masq_data = datastore->data;
2066 }
2067 if (!masq_data) {
2068 return -1;
2069 }
2070 ao2_ref(masq_data, +1);
2071
2072 /*
2073 * Someone likely forgot to do an ast_channel_publish_dial()
2074 * or ast_channel_publish_dial_forward() with a final dial
2075 * status on the channel.
2076 */
2077 ast_assert(masq_data->caller == caller);
2078
2079 /* Create peer target to put into datastore */
2080 target = ast_calloc(1, sizeof(*target));
2081 if (!target) {
2082 ao2_ref(masq_data, -1);
2083 return -1;
2084 }
2085 if (dialstring) {
2086 target->dialstring = ast_strdup(dialstring);
2087 if (!target->dialstring) {
2088 ast_free(target);
2089 ao2_ref(masq_data, -1);
2090 return -1;
2091 }
2092 }
2093 target->peer = ast_channel_ref(peer);
2094
2095 /* Put peer target into datastore */
2096 ao2_lock(masq_data);
2098 AST_LIST_INSERT_HEAD(&masq_data->dialed_peers, target, list);
2099 ao2_unlock(masq_data);
2100
2102 if (datastore) {
2103 if (datastore->data == masq_data) {
2104 /*
2105 * Peer already had the datastore for this dial masquerade.
2106 * This was a redundant peer dial masquerade setup.
2107 */
2108 ao2_ref(masq_data, -1);
2109 return 0;
2110 }
2111
2112 /* Something is wrong. Try to fix if the assert doesn't abort. */
2113 ast_assert(0);
2114
2115 /* Remove the stale dial masquerade datastore */
2118 ast_datastore_free(datastore);
2119 }
2120
2121 /* Create the peer dial masquerade datastore */
2122 if (dial_masquerade_datastore_add(peer, masq_data)) {
2123 /* Success */
2124 return 0;
2125 }
2126
2127 /* Failed to create the peer datastore */
2129 ao2_ref(masq_data, -1);
2130 return -1;
2131}
2132
2134{
2135 struct ast_datastore *datastore;
2136 struct dial_masquerade_datastore *masq_data;
2137
2138 datastore = dial_masquerade_datastore_find(peer);
2139 if (!datastore) {
2140 return;
2141 }
2142
2143 masq_data = datastore->data;
2144 if (masq_data) {
2146 }
2147
2148 ast_channel_datastore_remove(peer, datastore);
2149 ast_datastore_free(datastore);
2150}
2151
2153{
2154 struct ast_datastore *datastore;
2155 struct dial_masquerade_datastore *masq_data;
2156
2158 if (!datastore) {
2159 return;
2160 }
2161
2162 masq_data = datastore->data;
2163 if (!masq_data || !AST_LIST_EMPTY(&masq_data->dialed_peers)) {
2164 return;
2165 }
2166
2168
2170 ast_datastore_free(datastore);
2171}
char digit
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_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#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_RWLOCK
Definition: astobj2.h:365
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_wrlock(a)
Definition: astobj2.h:719
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#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
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
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_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ 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_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
Bridging API.
@ AST_BRIDGE_FLAG_INVISIBLE
static PGresult * result
Definition: cel_pgsql.c:84
static char language[MAX_LANGUAGE]
Definition: chan_iax2.c:324
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:473
static const char type[]
Definition: chan_ooh323.c:109
struct varshead * ast_channel_get_manager_vars(struct ast_channel *chan)
Gets the variables for a given channel, as specified by ast_channel_set_manager_vars().
Definition: channel.c:8005
const char * ast_channel_linkedid(const struct ast_channel *chan)
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_data(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2404
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2413
const char * ast_channel_tenantid(const struct ast_channel *chan)
struct ast_flags * ast_channel_snapshot_segment_flags(struct ast_channel *chan)
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1840
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
#define ast_channel_lock(chan)
Definition: channel.h:2968
struct varshead * ast_channel_get_ari_vars(struct ast_channel *chan)
Gets the variables for a given channel, as specified by ast_channel_set_ari_vars().
Definition: channel.c:8010
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snapshot *snapshot)
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2993
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_accountcode(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
const char * ast_channel_userfield(const struct ast_channel *chan)
#define ast_channel_trylock(chan)
Definition: channel.h:2970
const char * ast_channel_appl(const struct ast_channel *chan)
const char * ast_channel_peeraccount(const struct ast_channel *chan)
struct timeval ast_channel_creationtime(struct ast_channel *chan)
struct ast_channel_snapshot * ast_channel_snapshot(const struct ast_channel *chan)
enum ama_flags ast_channel_amaflags(const struct ast_channel *chan)
const char * ast_channel_hangupsource(const struct ast_channel *chan)
#define AST_NUM_CHANNEL_BUCKETS
Definition: channel.h:157
int ast_channel_hangupcause(const struct ast_channel *chan)
struct ast_bridge * ast_channel_get_bridge(const struct ast_channel *chan)
Get the bridge associated with a channel.
Definition: channel.c:10556
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
int ast_channel_has_manager_vars(void)
Return whether or not any manager variables have been set.
Definition: channel.c:7877
const char * ast_channel_language(const struct ast_channel *chan)
const char * ast_state2str(enum ast_channel_state state)
Gives the string form of a given channel state.
Definition: channel.c:636
@ AST_FLAG_SNAPSHOT_STAGE
Definition: channel.h:1070
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3015
const char * ast_channel_exten(const struct ast_channel *chan)
#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
ast_channel_state
ast_channel states
Definition: channelstate.h:35
static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, struct g726_state *state_ptr)
Definition: codec_g726.c:367
#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
Dialing API.
static const char name[]
Definition: format_mp3.c:68
direction
struct stasis_message_type * ast_channel_mixmonitor_mute_type(void)
Message type for muting or unmuting mixmonitor on a channel.
struct stasis_message_type * ast_channel_masquerade_type(void)
Message type for when a channel is being masqueraded.
struct ao2_container * ast_channel_cache_all(void)
void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
Publish a ast_channel_publish_varset for a channel.
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
struct stasis_message_type * ast_channel_hold_type(void)
Message type for when a channel is placed on hold.
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
struct stasis_message_type * ast_channel_talking_start(void)
Message type for a channel starting talking.
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
struct stasis_message_type * ast_channel_chanspy_start_type(void)
Message type for when a channel starts spying on another channel.
struct stasis_message_type * ast_channel_chanspy_stop_type(void)
Message type for when a channel stops spying on another channel.
struct stasis_message_type * ast_channel_talking_stop(void)
Message type for a channel stopping talking.
struct stasis_message_type * ast_channel_dtmf_begin_type(void)
Message type for when DTMF begins on a channel.
struct stasis_message_type * ast_channel_mixmonitor_stop_type(void)
Message type for stopping mixmonitor on a channel.
struct stasis_message_type * ast_channel_tone_detect(void)
Message type for a channel tone detection.
struct stasis_message_type * ast_channel_varset_type(void)
Message type for when a variable is set on a channel.
struct stasis_message_type * ast_channel_hangup_handler_type(void)
Message type for hangup handler related actions.
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
void ast_channel_snapshot_invalidate_segment(struct ast_channel *chan, enum ast_channel_snapshot_segment_invalidation segment)
Invalidate a channel snapshot segment from being reused.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest_by_name(const char *name)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring, const char *dialstatus)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
struct ao2_container * ast_multi_channel_blob_get_channels(struct ast_multi_channel_blob *obj, const char *role)
Retrieve all channel snapshots associated with a specific role from a ast_multi_channel_blob.
void ast_channel_publish_final_snapshot(struct ast_channel *chan)
Send the final channel snapshot for a channel, thus removing it from cache.
struct stasis_message_type * ast_channel_dial_type(void)
Message type for when a channel dials another channel.
struct stasis_message_type * ast_channel_moh_stop_type(void)
Message type for stopping music on hold on a channel.
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
struct stasis_message_type * ast_channel_unhold_type(void)
Message type for when a channel is removed from hold.
struct stasis_message_type * ast_channel_hangup_request_type(void)
Message type for when a hangup is requested on a channel.
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
struct stasis_message_type * ast_channel_flash_type(void)
Message type for when a hook flash occurs on a channel.
struct stasis_message_type * ast_channel_snapshot_type(void)
Message type for ast_channel_snapshot_update.
struct stasis_message * ast_channel_blob_create_from_cache(const char *channel_id, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
struct stasis_message_type * ast_channel_fax_type(void)
Message type for a fax operation.
struct stasis_message_type * ast_channel_dtmf_end_type(void)
Message type for when DTMF ends on a channel.
struct stasis_message_type * ast_channel_wink_type(void)
Message type for when a wink occurs on a channel.
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj.
ast_channel_snapshot_segment_invalidation
Channel snapshot invalidation flags, used to force generation of segments.
void ast_channel_publish_snapshot(struct ast_channel *chan)
Publish a ast_channel_snapshot for a channel.
struct ao2_container * ast_channel_cache_by_name(void)
Secondary channel cache, indexed by name.
void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring, const char *dialstatus, const char *forward)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
struct stasis_message_type * ast_channel_moh_start_type(void)
Message type for starting music on hold on a channel.
struct stasis_message * ast_channel_blob_create(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Creates a ast_channel_blob message.
struct stasis_message_type * ast_channel_mixmonitor_start_type(void)
Message type for starting mixmonitor on a channel.
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE
@ AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
Asterisk JSON abstraction layer.
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition: json.c:278
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition: json.c:399
struct ast_json * ast_json_name_number(const char *name, const char *number)
Common JSON rendering functions for common 'objects'.
Definition: json.c:646
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:670
struct ast_json * ast_json_dialplan_cep_app(const char *context, const char *exten, int priority, const char *app_name, const char *app_data)
Construct a context/exten/priority/application/application_data as JSON.
Definition: json.c:653
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition: json.c:414
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:332
struct ast_json * ast_json_channel_vars(struct varshead *channelvars)
Construct a JSON object from a ast_var_t list.
Definition: json.c:864
struct ast_json * ast_json_copy(const struct ast_json *value)
Copy a JSON value, but not its children.
Definition: json.c:637
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87
int ast_json_is_null(const struct ast_json *value)
Check if value is JSON null.
Definition: json.c:273
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#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
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:10126
#define EVENT_FLAG_CALL
Definition: manager.h:76
#define EVENT_FLAG_AGENT
Definition: manager.h:80
#define EVENT_FLAG_DIALPLAN
Definition: manager.h:86
Core PBX routines and definitions.
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
#define NULL
Definition: resample.c:96
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
Definition: stasis.c:618
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1512
const struct timeval * stasis_message_timestamp(const struct stasis_message *msg)
Get the time when a message was created.
static void channel_snapshot_dialplan_dtor(void *obj)
STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type)
Define channel message types.
int ast_channel_snapshot_connected_line_equal(const struct ast_channel_snapshot *old_snapshot, const struct ast_channel_snapshot *new_snapshot)
Compares the connected line info of two snapshots.
static struct ast_manager_event_blob * varset_to_ami(struct stasis_message *msg)
struct ast_json * ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_channel_snapshot.
static const struct ast_datastore_info dial_masquerade_caller_info
static struct ast_json * dtmf_end_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static struct ast_json * channel_blob_to_json(struct stasis_message *message, const char *type, const struct stasis_message_sanitizer *sanitize)
static void dial_masquerade_datastore_cleanup(struct dial_masquerade_datastore *masq_data)
static int set_dial_masquerade(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring)
static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
static void channel_blob_dtor(void *obj)
static int channel_role_cmp_cb(void *obj, void *arg, int flags)
static struct ast_channel_snapshot_caller * channel_snapshot_caller_create(struct ast_channel *chan)
static void publish_message_for_channel_topics(struct stasis_message *message, struct ast_channel *chan)
static void dial_target_free(struct dial_target *doomed)
static void dial_masquerade_caller_datastore_destroy(void *data)
static const struct ast_datastore_info dial_masquerade_info
static int channel_snapshot_uniqueid_cmp_cb(void *obj, void *arg, int flags)
static struct ast_json * tone_detect_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static void dial_masquerade_datastore_remove_chan(struct dial_masquerade_datastore *masq_data, struct ast_channel *chan)
static struct ast_json * talking_start_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static struct stasis_message * create_channel_blob_message(struct ast_channel_snapshot *snapshot, struct stasis_message_type *type, struct ast_json *blob)
static struct ast_channel_snapshot_base * channel_snapshot_base_create(struct ast_channel *chan)
static void ast_channel_publish_dial_internal(struct ast_channel *caller, struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring, const char *dialstatus, const char *forward)
static struct ao2_container * channel_cache_by_name
#define NUM_MULTI_CHANNEL_BLOB_BUCKETS
static void dial_masquerade_breakdown(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
static void dial_masquerade_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
static struct ast_channel_snapshot_update * channel_snapshot_update_create(struct ast_channel *chan)
static struct dial_masquerade_datastore * dial_masquerade_datastore_add(struct ast_channel *chan, struct dial_masquerade_datastore *masq_data)
int ast_channel_snapshot_caller_id_equal(const struct ast_channel_snapshot *old_snapshot, const struct ast_channel_snapshot *new_snapshot)
Compares the callerid info of two snapshots.
static struct ast_channel_snapshot_peer * channel_snapshot_peer_create(struct ast_channel *chan)
static struct ast_datastore * dial_masquerade_datastore_find(struct ast_channel *chan)
static struct ast_json * varset_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static void channel_snapshot_update_dtor(void *obj)
static struct ast_json * dial_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
int ast_stasis_channels_init(void)
Initialize the stasis channel topic and message types.
static struct ast_manager_event_blob * talking_stop_to_ami(struct stasis_message *msg)
int ast_channel_snapshot_cep_equal(const struct ast_channel_snapshot *old_snapshot, const struct ast_channel_snapshot *new_snapshot)
Compares the context, exten and priority of two snapshots.
static struct stasis_topic * channel_topic_all
static void dial_masquerade_datastore_destroy(void *data)
static void remove_dial_masquerade_caller(struct ast_channel *caller)
static struct ast_channel_snapshot_connected * channel_snapshot_connected_create(struct ast_channel *chan)
static struct ast_manager_event_blob * talking_start_to_ami(struct stasis_message *msg)
static struct ast_channel_snapshot_dialplan * channel_snapshot_dialplan_create(struct ast_channel *chan)
static struct dial_masquerade_datastore * dial_masquerade_datastore_alloc(void)
static void dial_masquerade_datastore_dtor(void *vdoomed)
static void channel_role_snapshot_dtor(void *obj)
static struct ast_channel_snapshot_hangup * channel_snapshot_hangup_create(struct ast_channel *chan)
static int channel_snapshot_uniqueid_hash_cb(const void *obj, const int flags)
static void channel_snapshot_caller_dtor(void *obj)
static void channel_snapshot_dtor(void *obj)
static struct ao2_container * channel_cache
static void channel_snapshot_base_dtor(void *obj)
static struct ast_json * hold_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static void remove_dial_masquerade(struct ast_channel *peer)
static struct ast_manager_event_blob * agent_logoff_to_ami(struct stasis_message *msg)
static struct ast_json * unhold_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static int channel_snapshot_hash_cb(const void *obj, const int flags)
static int channel_role_hash_cb(const void *obj, const int flags)
static struct ast_json * hangup_request_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static void multi_channel_blob_dtor(void *obj)
static struct ast_json * talking_stop_to_json(struct stasis_message *message, const struct stasis_message_sanitizer *sanitize)
static struct ast_manager_event_blob * agent_login_to_ami(struct stasis_message *msg)
static struct ast_channel_snapshot_bridge * channel_snapshot_bridge_create(struct ast_channel *chan)
static void stasis_channels_cleanup(void)
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_init_extended(x, field)
Initialize an extended string field.
Definition: stringfields.h:401
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
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
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_escape_c_alloc(const char *s)
Escape standard 'C' sequences in the given string.
Definition: utils.c:2140
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
Structure that contains information about a bridge.
Definition: bridge.h:349
const ast_string_field uniqueid
Definition: bridge.h:401
struct ast_flags feature_flags
Definition: bridge.h:369
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
Structure containing base information for a channel snapshot.
const ast_string_field language
const ast_string_field tenantid
const ast_string_field accountcode
const ast_string_field userfield
const ast_string_field uniqueid
const ast_string_field name
Structure containing bridge information for a channel snapshot.
Structure containing caller information for a channel snapshot.
const ast_string_field dialed_subaddr
const ast_string_field number
const ast_string_field rdnis
const ast_string_field ani
const ast_string_field name
const ast_string_field subaddr
const ast_string_field dnid
Structure containing connected information for a channel snapshot.
Structure containing dialplan information for a channel snapshot.
const ast_string_field data
const ast_string_field context
const ast_string_field exten
const ast_string_field appl
Structure containing hangup information for a channel snapshot.
Structure containing peer information for a channel snapshot.
Structure representing a change of snapshot of channel state.
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_connected * connected
struct varshead * manager_vars
struct varshead * ari_vars
struct ast_channel_snapshot_dialplan * dialplan
struct ast_channel_snapshot_peer * peer
struct ast_channel_snapshot_bridge * bridge
struct ast_channel_snapshot_base * base
enum ast_channel_state state
struct ast_flags softhangup_flags
struct ast_channel_snapshot_caller * caller
struct ast_flags flags
struct ast_channel_snapshot_hangup * hangup
Main Channel structure associated with a channel.
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
Abstract JSON element (object, array, string, int, ...).
Struct containing info for an AMI event to send out.
Definition: manager.h:502
A multi channel blob data structure for multi_channel_blob stasis messages.
struct ast_json * blob
struct ao2_container * channel_snapshots
char * str
Subscriber phone number (Malloced)
Definition: channel.h:388
Support for dynamic strings.
Definition: strings.h:623
A channel snapshot wrapper object used in ast_multi_channel_blob objects.
struct ast_channel_snapshot * snapshot
struct ast_channel * caller
struct dial_masquerade_datastore::@398 dialed_peers
struct ast_channel * peer
struct dial_target::@397 list
Definition: astman.c:222
Number structure.
Definition: app_followme.c:154
Structure containing callbacks for Stasis message sanitization.
Definition: stasis.h:200
int(* channel_snapshot)(const struct ast_channel_snapshot *snapshot)
Callback which determines whether a channel should be sanitized from a message based on the channel's...
Definition: stasis.h:221
int value
Definition: syslog.c:37
Support for translation of data formats. translate.c.
UTF-8 information and validation functions.
ast_utf8_replace_result
Definition: utf8.h:70
@ AST_UTF8_REPLACE_VALID
Source contained fully valid UTF-8.
Definition: utf8.h:76
enum ast_utf8_replace_result ast_utf8_replace_invalid_chars(char *dst, size_t *dst_size, const char *src, size_t src_len)
Copy a string safely replacing any invalid UTF-8 sequences.
Definition: utf8.c:173
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_assert(a)
Definition: utils.h:739
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ast_copy_flags(dest, src, flagz)
Definition: utils.h:84
#define AST_FLAGS_ALL
Definition: utils.h:196