Asterisk - The Open Source Telephony Project GIT-master-67613d1
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
288
289 snapshot->creationtime = ast_channel_creationtime(chan);
291
292 if (ast_channel_tech(chan)->get_pvt_uniqueid) {
293 ast_string_field_set(snapshot, protocol_id, ast_channel_tech(chan)->get_pvt_uniqueid(chan));
294 }
295
296 return snapshot;
297}
298
300{
301 const char *linkedid = S_OR(ast_channel_linkedid(chan), "");
302 const char *peeraccount = S_OR(ast_channel_peeraccount(chan), "");
303 size_t linkedid_len = strlen(linkedid) + 1;
304 size_t peeraccount_len = strlen(peeraccount) + 1;
305 struct ast_channel_snapshot_peer *snapshot;
306
307 snapshot = ao2_alloc_options(sizeof(*snapshot) + linkedid_len + peeraccount_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
308 if (!snapshot) {
309 return NULL;
310 }
311
312 strcpy(snapshot->account, peeraccount); /* Safe */
313 snapshot->linkedid = snapshot->account + peeraccount_len;
314 ast_copy_string(snapshot->linkedid, linkedid, linkedid_len); /* Safe */
315
316 return snapshot;
317}
318
319static void channel_snapshot_caller_dtor(void *obj)
320{
321 struct ast_channel_snapshot_caller *snapshot = obj;
322
324}
325
327{
328 struct ast_channel_snapshot_caller *snapshot;
329
330 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_caller_dtor,
332 if (!snapshot) {
333 return NULL;
334 }
335
336 if (ast_string_field_init(snapshot, 256)) {
337 ao2_ref(snapshot, -1);
338 return NULL;
339 }
340
341 ast_string_field_set(snapshot, name,
342 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
344 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
346 S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, ""));
347 ast_string_field_set(snapshot, ani,
348 S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
349
350 ast_string_field_set(snapshot, rdnis,
351 S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
352
353 ast_string_field_set(snapshot, dnid,
354 S_OR(ast_channel_dialed(chan)->number.str, ""));
356 S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
357
358 snapshot->pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
359
360 return snapshot;
361}
362
364{
365 const char *name = S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "");
366 const char *number = S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "");
367 size_t name_len = strlen(name) + 1;
368 size_t number_len = strlen(number) + 1;
369 struct ast_channel_snapshot_connected *snapshot;
370
371 snapshot = ao2_alloc_options(sizeof(*snapshot) + name_len + number_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
372 if (!snapshot) {
373 return NULL;
374 }
375
376 strcpy(snapshot->name, name); /* Safe */
377 snapshot->number = snapshot->name + name_len;
378 ast_copy_string(snapshot->number, number, number_len); /* Safe */
379
380 return snapshot;
381}
382
384{
385 const char *uniqueid = "";
386 struct ast_bridge *bridge;
387 struct ast_channel_snapshot_bridge *snapshot;
388
389 bridge = ast_channel_get_bridge(chan);
390 if (bridge && !ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
391 uniqueid = bridge->uniqueid;
392 }
393 ao2_cleanup(bridge);
394
395 snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(uniqueid) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
396 if (!snapshot) {
397 return NULL;
398 }
399
400 strcpy(snapshot->id, uniqueid); /* Safe */
401
402 return snapshot;
403}
404
405static void channel_snapshot_dialplan_dtor(void *obj)
406{
407 struct ast_channel_snapshot_dialplan *snapshot = obj;
408
410}
411
413{
414 struct ast_channel_snapshot_dialplan *snapshot;
415
416 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dialplan_dtor,
418 if (!snapshot) {
419 return NULL;
420 }
421
422 if (ast_string_field_init(snapshot, 256)) {
423 ao2_ref(snapshot, -1);
424 return NULL;
425 }
426
427 if (ast_channel_appl(chan)) {
429 }
430 if (ast_channel_data(chan)) {
432 }
435 snapshot->priority = ast_channel_priority(chan);
436
437 return snapshot;
438}
439
441{
442 const char *hangupsource = S_OR(ast_channel_hangupsource(chan), "");
443 struct ast_channel_snapshot_hangup *snapshot;
444
445 snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(hangupsource) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
446 if (!snapshot) {
447 return NULL;
448 }
449
450 snapshot->cause = ast_channel_hangupcause(chan);
451 strcpy(snapshot->source, hangupsource); /* Safe */
452
453 return snapshot;
454}
455
457{
458 struct ast_channel_snapshot *old_snapshot;
459 struct ast_channel_snapshot *snapshot;
460
461 /* no snapshots for dummy channels */
462 if (!ast_channel_tech(chan)) {
463 return NULL;
464 }
465
466 snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dtor,
468 if (!snapshot) {
469 return NULL;
470 }
471
472 old_snapshot = ast_channel_snapshot(chan);
473
474 /* Channels automatically have all segments invalidated on them initially so a check for an old
475 * snapshot existing before usage is not done here, as it can not happen. If the stored snapshot
476 * on the channel is updated as a result of this then all segments marked as invalidated will be
477 * cleared.
478 */
480 /* The base information has changed so update our snapshot */
481 snapshot->base = channel_snapshot_base_create(chan);
482 if (!snapshot->base) {
483 ao2_ref(snapshot, -1);
484 return NULL;
485 }
486 } else {
487 snapshot->base = ao2_bump(old_snapshot->base);
488 }
489
491 /* The peer information has changed so update our snapshot */
492 snapshot->peer = channel_snapshot_peer_create(chan);
493 if (!snapshot->peer) {
494 ao2_ref(snapshot, -1);
495 return NULL;
496 }
497 } else {
498 snapshot->peer = ao2_bump(old_snapshot->peer);
499 }
500
501 /* Unfortunately both caller and connected information do not have an enforced contract with
502 * the channel API. This has allowed consumers to directly get the caller or connected structure
503 * and manipulate it. Until such time as there is an enforced contract (which is being tracked under
504 * ASTERISK-28164) they are each regenerated every time a channel snapshot is created.
505 */
506 snapshot->caller = channel_snapshot_caller_create(chan);
507 if (!snapshot->caller) {
508 ao2_ref(snapshot, -1);
509 return NULL;
510 }
511
513 if (!snapshot->connected) {
514 ao2_ref(snapshot, -1);
515 return NULL;
516 }
517
519 /* The bridge has changed so update our snapshot */
520 snapshot->bridge = channel_snapshot_bridge_create(chan);
521 if (!snapshot->bridge) {
522 ao2_ref(snapshot, -1);
523 return NULL;
524 }
525 } else {
526 snapshot->bridge = ao2_bump(old_snapshot->bridge);
527 }
528
530 /* The dialplan information has changed so update our snapshot */
532 if (!snapshot->dialplan) {
533 ao2_ref(snapshot, -1);
534 return NULL;
535 }
536 } else {
537 snapshot->dialplan = ao2_bump(old_snapshot->dialplan);
538 }
539
541 /* The hangup information has changed so update our snapshot */
542 snapshot->hangup = channel_snapshot_hangup_create(chan);
543 if (!snapshot->hangup) {
544 ao2_ref(snapshot, -1);
545 return NULL;
546 }
547 } else {
548 snapshot->hangup = ao2_bump(old_snapshot->hangup);
549 }
550
551 snapshot->state = ast_channel_state(chan);
552 snapshot->amaflags = ast_channel_amaflags(chan);
553 ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
555
556 /* These have to be recreated as they may have changed, unfortunately */
558 snapshot->ari_vars = ast_channel_get_ari_vars(chan);
559
560 return snapshot;
561}
562
563static void channel_snapshot_update_dtor(void *obj)
564{
566
567 ao2_cleanup(update->old_snapshot);
568 ao2_cleanup(update->new_snapshot);
569}
570
572{
574
577 if (!update) {
578 return NULL;
579 }
580
581 update->old_snapshot = ao2_bump(ast_channel_snapshot(chan));
582 update->new_snapshot = ast_channel_snapshot_create(chan);
583 if (!update->new_snapshot) {
584 ao2_ref(update, -1);
585 return NULL;
586 }
587
588 return update;
589}
590
592{
593 if (chan) {
595 } else {
597 }
598}
599
600static void channel_blob_dtor(void *obj)
601{
602 struct ast_channel_blob *event = obj;
603 ao2_cleanup(event->snapshot);
604 ast_json_unref(event->blob);
605}
606
608 struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring,
609 const char *dialstatus, const char *forward)
610{
611 struct ast_multi_channel_blob *payload;
612 struct stasis_message *msg;
613 struct ast_json *blob;
614 struct ast_channel_snapshot *peer_snapshot;
615
616 if (!ast_channel_dial_type()) {
617 return;
618 }
619
620 ast_assert(peer != NULL);
621
622 blob = ast_json_pack("{s: s, s: s, s: s}",
623 "dialstatus", S_OR(dialstatus, ""),
624 "forward", S_OR(forward, ""),
625 "dialstring", S_OR(dialstring, ""));
626 if (!blob) {
627 return;
628 }
629 payload = ast_multi_channel_blob_create(blob);
630 ast_json_unref(blob);
631 if (!payload) {
632 return;
633 }
634
635 if (caller) {
636 struct ast_channel_snapshot *caller_snapshot;
637
639 if (ast_strlen_zero(dialstatus)) {
641 } else {
642 caller_snapshot = ast_channel_snapshot_create(caller);
643 }
645 if (!caller_snapshot) {
646 ao2_ref(payload, -1);
647 return;
648 }
649 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
650 ao2_ref(caller_snapshot, -1);
651 }
652
654 if (ast_strlen_zero(dialstatus)) {
656 } else {
657 peer_snapshot = ast_channel_snapshot_create(peer);
658 }
660 if (!peer_snapshot) {
661 ao2_ref(payload, -1);
662 return;
663 }
664 ast_multi_channel_blob_add_channel(payload, "peer", peer_snapshot);
665 ao2_ref(peer_snapshot, -1);
666
667 if (forwarded) {
668 struct ast_channel_snapshot *forwarded_snapshot;
669
670 ast_channel_lock(forwarded);
671 forwarded_snapshot = ast_channel_snapshot_create(forwarded);
672 ast_channel_unlock(forwarded);
673 if (!forwarded_snapshot) {
674 ao2_ref(payload, -1);
675 return;
676 }
677 ast_multi_channel_blob_add_channel(payload, "forwarded", forwarded_snapshot);
678 ao2_ref(forwarded_snapshot, -1);
679 }
680
682 ao2_ref(payload, -1);
683 if (msg) {
685 ao2_ref(msg, -1);
686 }
687}
688
689static void remove_dial_masquerade(struct ast_channel *peer);
691static int set_dial_masquerade(struct ast_channel *caller,
692 struct ast_channel *peer, const char *dialstring);
693
695 struct ast_channel *forwarded, const char *dialstring, const char *dialstatus,
696 const char *forward)
697{
698 ast_assert(peer != NULL);
699
700 /* XXX With an early bridge the below dial masquerade datastore code could, theoretically,
701 * go away as the act of changing the channel during dialing would be done using the bridge
702 * API itself and not a masquerade.
703 */
704
705 if (caller) {
706 /*
707 * Lock two or three channels.
708 *
709 * We need to hold the locks to hold off a potential masquerade
710 * messing up the stasis dial event ordering.
711 */
712 for (;; ast_channel_unlock(caller), sched_yield()) {
715 continue;
716 }
717 if (forwarded && ast_channel_trylock(forwarded)) {
719 continue;
720 }
721 break;
722 }
723
724 if (ast_strlen_zero(dialstatus)) {
725 set_dial_masquerade(caller, peer, dialstring);
726 } else {
728 }
729 }
730
731 ast_channel_publish_dial_internal(caller, peer, forwarded, dialstring, dialstatus,
732 forward);
733
734 if (caller) {
735 if (forwarded) {
736 ast_channel_unlock(forwarded);
737 }
741 }
742}
743
745 const char *dialstring, const char *dialstatus)
746{
747 ast_channel_publish_dial_forward(caller, peer, NULL, dialstring, dialstatus, NULL);
748}
749
752 struct ast_json *blob)
753{
754 struct stasis_message *msg;
755 struct ast_channel_blob *obj;
756
757 obj = ao2_alloc(sizeof(*obj), channel_blob_dtor);
758 if (!obj) {
759 return NULL;
760 }
761
762 if (snapshot) {
763 obj->snapshot = snapshot;
764 ao2_ref(obj->snapshot, +1);
765 }
766 if (!blob) {
768 }
769 obj->blob = ast_json_ref(blob);
770
771 msg = stasis_message_create(type, obj);
772 ao2_cleanup(obj);
773 return msg;
774}
775
778 struct ast_json *blob)
779{
780 struct ast_channel_snapshot *snapshot;
781 struct stasis_message *msg;
782
783 if (!type) {
784 return NULL;
785 }
786
787 snapshot = ast_channel_snapshot_get_latest(channel_id);
788 msg = create_channel_blob_message(snapshot, type, blob);
789 ao2_cleanup(snapshot);
790 return msg;
791}
792
794 struct stasis_message_type *type, struct ast_json *blob)
795{
796 struct ast_channel_snapshot *snapshot;
797 struct stasis_message *msg;
798
799 if (!type) {
800 return NULL;
801 }
802
803 snapshot = chan ? ao2_bump(ast_channel_snapshot(chan)) : NULL;
804 msg = create_channel_blob_message(snapshot, type, blob);
805 ao2_cleanup(snapshot);
806 return msg;
807}
808
809/*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */
811 struct ast_channel_snapshot *snapshot; /*!< A channel snapshot */
812 char role[0]; /*!< The role assigned to the channel */
813};
814
815/*! \brief A multi channel blob data structure for multi_channel_blob stasis messages */
817 struct ao2_container *channel_snapshots; /*!< A container holding the snapshots */
818 struct ast_json *blob; /*!< A blob of JSON data */
819};
820
821/*!
822 * \internal
823 * \brief Comparison function for \ref channel_role_snapshot objects
824 */
825static int channel_role_cmp_cb(void *obj, void *arg, int flags)
826{
827 const struct channel_role_snapshot *object_left = obj;
828 const struct channel_role_snapshot *object_right = arg;
829 const char *right_key = arg;
830 int cmp;
831
832 switch (flags & OBJ_SEARCH_MASK) {
834 right_key = object_right->role;
835 case OBJ_SEARCH_KEY:
836 cmp = strcasecmp(object_left->role, right_key);
837 break;
839 cmp = strncasecmp(object_left->role, right_key, strlen(right_key));
840 break;
841 default:
842 cmp = 0;
843 break;
844 }
845 if (cmp) {
846 return 0;
847 }
848 return CMP_MATCH;
849}
850
851/*!
852 * \internal
853 * \brief Hash function for \ref channel_role_snapshot objects
854 */
855static int channel_role_hash_cb(const void *obj, const int flags)
856{
857 const struct channel_role_snapshot *object = obj;
858 const char *key;
859
860 switch (flags & OBJ_SEARCH_MASK) {
861 case OBJ_SEARCH_KEY:
862 key = obj;
863 break;
865 key = object->role;
866 break;
867 default:
868 ast_assert(0);
869 return 0;
870 }
871 return ast_str_case_hash(key);
872}
873
874/*!
875 * \internal
876 * \brief Destructor for \ref ast_multi_channel_blob objects
877 */
878static void multi_channel_blob_dtor(void *obj)
879{
880 struct ast_multi_channel_blob *multi_blob = obj;
881
882 ao2_cleanup(multi_blob->channel_snapshots);
883 ast_json_unref(multi_blob->blob);
884}
885
887{
888 struct ast_multi_channel_blob *obj;
889
890 ast_assert(blob != NULL);
891
892 obj = ao2_alloc(sizeof(*obj), multi_channel_blob_dtor);
893 if (!obj) {
894 return NULL;
895 }
896
899 if (!obj->channel_snapshots) {
900 ao2_ref(obj, -1);
901 return NULL;
902 }
903
904 obj->blob = ast_json_ref(blob);
905 return obj;
906}
907
909{
910 ast_assert(!ast_strlen_zero(uniqueid));
911
912 return ao2_find(channel_cache, uniqueid, OBJ_SEARCH_KEY);
913}
914
916{
918
920}
921
923{
925 struct stasis_message *message;
926
928 return;
929 }
930
932 if (!update) {
933 return;
934 }
935
937 /* In the success path message holds a reference to update so it will be valid
938 * for the lifetime of this function until the end.
939 */
940 ao2_ref(update, -1);
941 if (!message) {
942 return;
943 }
944
945 ao2_unlink(channel_cache, update->old_snapshot);
947
949
951 ao2_ref(message, -1);
952}
953
954static void channel_role_snapshot_dtor(void *obj)
955{
956 struct channel_role_snapshot *role_snapshot = obj;
957
958 ao2_cleanup(role_snapshot->snapshot);
959}
960
962{
963 struct channel_role_snapshot *role_snapshot;
964 int role_len = strlen(role) + 1;
965
966 if (!obj || ast_strlen_zero(role) || !snapshot) {
967 return;
968 }
969
970 role_snapshot = ao2_alloc_options(sizeof(*role_snapshot) + role_len,
972 if (!role_snapshot) {
973 return;
974 }
975 ast_copy_string(role_snapshot->role, role, role_len);
976 role_snapshot->snapshot = snapshot;
977 ao2_ref(role_snapshot->snapshot, +1);
978 ao2_link(obj->channel_snapshots, role_snapshot);
979 ao2_ref(role_snapshot, -1);
980}
981
983{
984 struct channel_role_snapshot *role_snapshot;
985 struct ast_channel_snapshot *snapshot;
986
987 if (!obj || ast_strlen_zero(role)) {
988 return NULL;
989 }
990 role_snapshot = ao2_find(obj->channel_snapshots, role, OBJ_SEARCH_KEY);
991 /* Note that this function does not increase the ref count on snapshot */
992 if (!role_snapshot) {
993 return NULL;
994 }
995 snapshot = role_snapshot->snapshot;
996 ao2_ref(role_snapshot, -1);
997 return snapshot;
998}
999
1001{
1002 struct ao2_container *ret_container;
1003 struct ao2_iterator *it_role_snapshots;
1004 struct channel_role_snapshot *role_snapshot;
1005 char *arg;
1006
1007 if (!obj || ast_strlen_zero(role)) {
1008 return NULL;
1009 }
1010
1014 if (!ret_container) {
1015 return NULL;
1016 }
1017
1018 arg = ast_strdupa(role);
1019 it_role_snapshots = ao2_callback(obj->channel_snapshots,
1021 if (!it_role_snapshots) {
1022 ao2_ref(ret_container, -1);
1023 return NULL;
1024 }
1025
1026 while ((role_snapshot = ao2_iterator_next(it_role_snapshots))) {
1027 ao2_link(ret_container, role_snapshot->snapshot);
1028 ao2_ref(role_snapshot, -1);
1029 }
1030 ao2_iterator_destroy(it_role_snapshots);
1031
1032 return ret_container;
1033}
1034
1036{
1037 if (!obj) {
1038 return NULL;
1039 }
1040 return obj->blob;
1041}
1042
1044{
1046}
1047
1049{
1052}
1053
1056{
1058}
1059
1061{
1063 struct stasis_message *message;
1064
1066 return;
1067 }
1068
1070 return;
1071 }
1072
1074 if (!update) {
1075 return;
1076 }
1077
1078 /* If an old snapshot exists and is the same as this newly created one don't bother
1079 * raising a message as it hasn't changed.
1080 */
1081 if (update->old_snapshot && !memcmp(update->old_snapshot, update->new_snapshot, sizeof(struct ast_channel_snapshot))) {
1082 ao2_ref(update, -1);
1083 return;
1084 }
1085
1087 /* In the success path message holds a reference to update so it will be valid
1088 * for the lifetime of this function until the end.
1089 */
1090 ao2_ref(update, -1);
1091 if (!message) {
1092 return;
1093 }
1094
1095 /* We lock these ourselves so that the update is atomic and there isn't time where a
1096 * snapshot is not in the cache.
1097 */
1099 if (update->old_snapshot) {
1101 }
1104
1105 /* The same applies here. */
1107 if (update->old_snapshot) {
1109 }
1112
1113 ast_channel_snapshot_set(chan, update->new_snapshot);
1114
1115 /* As this is now the new snapshot any existing invalidated segments have been
1116 * created fresh and are up to date.
1117 */
1119
1122 ao2_ref(message, -1);
1123}
1124
1126{
1127 struct stasis_message *message;
1128
1129 if (!blob) {
1130 blob = ast_json_null();
1131 }
1132
1134 if (message) {
1136 ao2_ref(message, -1);
1137 }
1138}
1139
1141{
1142 struct stasis_message *message;
1143
1144 if (!blob) {
1145 blob = ast_json_null();
1146 }
1147
1148 message = ast_channel_blob_create(chan, type, blob);
1149 if (message) {
1151 ao2_ref(message, -1);
1152 }
1153}
1154
1155void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
1156{
1157 struct ast_json *blob;
1159 char *new_value = NULL;
1160 size_t new_value_size = 0;
1161
1162 ast_assert(name != NULL);
1163 ast_assert(value != NULL);
1164
1165 /*
1166 * Call with new-value == NULL to just check for invalid UTF-8
1167 * sequences and get size of buffer needed.
1168 */
1169 result = ast_utf8_replace_invalid_chars(new_value, &new_value_size,
1170 value, strlen(value));
1171
1173 /*
1174 * If there were no invalid sequences, we can use
1175 * the value directly.
1176 */
1177 new_value = (char *)value;
1178 } else {
1179 /*
1180 * If there were invalid sequences, we need to replace
1181 * them with the UTF-8 U+FFFD replacement character.
1182 */
1183 new_value = ast_alloca(new_value_size);
1184
1185 result = ast_utf8_replace_invalid_chars(new_value, &new_value_size,
1186 value, strlen(value));
1187
1188 ast_log(LOG_WARNING, "%s: The contents of variable '%s' had invalid UTF-8 sequences which were replaced",
1189 ast_channel_name(chan), name);
1190 }
1191
1192 blob = ast_json_pack("{s: s, s: s}",
1193 "variable", name,
1194 "value", new_value);
1195 if (!blob) {
1196 ast_log(LOG_ERROR, "Error creating message\n");
1197 return;
1198 }
1199
1200 /*! If there are manager variables, force a cache update */
1201 if (chan && ast_channel_has_manager_vars()) {
1203 }
1204
1205 /* This function is NULL safe for global variables */
1207 ast_json_unref(blob);
1208}
1209
1211{
1212 struct ast_str *channel_event_string;
1213 struct ast_channel_blob *obj = stasis_message_data(msg);
1214 const char *variable =
1215 ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
1216 char *value;
1217 struct ast_manager_event_blob *ev;
1218
1220 "value")));
1221 if (!value) {
1222 return NULL;
1223 }
1224
1225 if (obj->snapshot) {
1226 channel_event_string = ast_manager_build_channel_state_string(obj->snapshot);
1227 } else {
1228 channel_event_string = ast_str_create(35);
1229 ast_str_set(&channel_event_string, 0,
1230 "Channel: none\r\n"
1231 "Uniqueid: none\r\n");
1232 }
1233 if (!channel_event_string) {
1234 ast_free(value);
1235 return NULL;
1236 }
1237
1239 "%s"
1240 "Variable: %s\r\n"
1241 "Value: %s\r\n",
1242 ast_str_buffer(channel_event_string), variable, value);
1243 ast_free(channel_event_string);
1244 ast_free(value);
1245 return ev;
1246}
1247
1249{
1250 struct ast_str *channel_string;
1251 struct ast_channel_blob *obj = stasis_message_data(msg);
1252 const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
1253 struct ast_manager_event_blob *ev;
1254
1255 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1256 if (!channel_string) {
1257 return NULL;
1258 }
1259
1261 "%s"
1262 "Agent: %s\r\n",
1263 ast_str_buffer(channel_string), agent);
1264 ast_free(channel_string);
1265 return ev;
1266}
1267
1269{
1270 struct ast_str *channel_string;
1271 struct ast_channel_blob *obj = stasis_message_data(msg);
1272 const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
1273 long logintime = ast_json_integer_get(ast_json_object_get(obj->blob, "logintime"));
1274 struct ast_manager_event_blob *ev;
1275
1276 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1277 if (!channel_string) {
1278 return NULL;
1279 }
1280
1282 "%s"
1283 "Agent: %s\r\n"
1284 "Logintime: %ld\r\n",
1285 ast_str_buffer(channel_string), agent, logintime);
1286 ast_free(channel_string);
1287 return ev;
1288}
1289
1291 const struct ast_channel_snapshot *snapshot,
1292 const struct stasis_message_sanitizer *sanitize)
1293{
1294 struct ast_json *json_chan;
1295
1296 if (snapshot == NULL
1297 || (sanitize
1298 && sanitize->channel_snapshot
1299 && sanitize->channel_snapshot(snapshot))) {
1300 return NULL;
1301 }
1302
1303 json_chan = ast_json_pack(
1304 /* Broken up into groups for readability */
1305 "{ s: s, s: s, s: s, s: s,"
1306 " s: o, s: o, s: s,"
1307 " s: o, s: o, s: s }",
1308 /* First line */
1309 "id", snapshot->base->uniqueid,
1310 "name", snapshot->base->name,
1311 "state", ast_state2str(snapshot->state),
1312 "protocol_id", snapshot->base->protocol_id,
1313 /* Second line */
1314 "caller", ast_json_name_number(
1315 snapshot->caller->name, snapshot->caller->number),
1316 "connected", ast_json_name_number(
1317 snapshot->connected->name, snapshot->connected->number),
1318 "accountcode", snapshot->base->accountcode,
1319 /* Third line */
1320 "dialplan", ast_json_dialplan_cep_app(
1321 snapshot->dialplan->context, snapshot->dialplan->exten, snapshot->dialplan->priority,
1322 snapshot->dialplan->appl, snapshot->dialplan->data),
1323 "creationtime", ast_json_timeval(snapshot->base->creationtime, NULL),
1324 "language", snapshot->base->language);
1325
1326 if (!ast_strlen_zero(snapshot->caller->rdnis)) {
1327 ast_json_object_set(json_chan, "caller_rdnis", ast_json_string_create(snapshot->caller->rdnis));
1328 }
1329
1330 if (snapshot->ari_vars && !AST_LIST_EMPTY(snapshot->ari_vars)) {
1331 ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars));
1332 }
1333
1334 return json_chan;
1335}
1336
1338 const struct ast_channel_snapshot *old_snapshot,
1339 const struct ast_channel_snapshot *new_snapshot)
1340{
1341 ast_assert(old_snapshot != NULL);
1342 ast_assert(new_snapshot != NULL);
1343
1344 /* We actually get some snapshots with CEP set, but before the
1345 * application is set. Since empty application is invalid, we treat
1346 * setting the application from nothing as a CEP change.
1347 */
1348 if (ast_strlen_zero(old_snapshot->dialplan->appl) &&
1349 !ast_strlen_zero(new_snapshot->dialplan->appl)) {
1350 return 0;
1351 }
1352
1353 return old_snapshot->dialplan->priority == new_snapshot->dialplan->priority &&
1354 strcmp(old_snapshot->dialplan->context, new_snapshot->dialplan->context) == 0 &&
1355 strcmp(old_snapshot->dialplan->exten, new_snapshot->dialplan->exten) == 0;
1356}
1357
1359 const struct ast_channel_snapshot *old_snapshot,
1360 const struct ast_channel_snapshot *new_snapshot)
1361{
1362 ast_assert(old_snapshot != NULL);
1363 ast_assert(new_snapshot != NULL);
1364 return strcmp(old_snapshot->caller->number, new_snapshot->caller->number) == 0 &&
1365 strcmp(old_snapshot->caller->name, new_snapshot->caller->name) == 0;
1366}
1367
1369 const struct ast_channel_snapshot *old_snapshot,
1370 const struct ast_channel_snapshot *new_snapshot)
1371{
1372 ast_assert(old_snapshot != NULL);
1373 ast_assert(new_snapshot != NULL);
1374 return strcmp(old_snapshot->connected->number, new_snapshot->connected->number) == 0 &&
1375 strcmp(old_snapshot->connected->name, new_snapshot->connected->name) == 0;
1376}
1377
1379 struct stasis_message *message,
1380 const char *type,
1381 const struct stasis_message_sanitizer *sanitize)
1382{
1383 struct ast_json *to_json;
1384 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1385 struct ast_json *blob = channel_blob->blob;
1386 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1387 const struct timeval *tv = stasis_message_timestamp(message);
1388 int res = 0;
1389
1390 if (blob == NULL || ast_json_is_null(blob)) {
1391 to_json = ast_json_object_create();
1392 } else {
1393 /* blobs are immutable, so shallow copies are fine */
1394 to_json = ast_json_copy(blob);
1395 }
1396 if (!to_json) {
1397 return NULL;
1398 }
1399
1400 res |= ast_json_object_set(to_json, "type", ast_json_string_create(type));
1401 res |= ast_json_object_set(to_json, "timestamp",
1402 ast_json_timeval(*tv, NULL));
1403
1404 /* For global channel messages, the snapshot is optional */
1405 if (snapshot) {
1406 struct ast_json *json_channel;
1407
1408 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1409 if (!json_channel) {
1410 ast_json_unref(to_json);
1411 return NULL;
1412 }
1413
1414 res |= ast_json_object_set(to_json, "channel", json_channel);
1415 }
1416
1417 if (res != 0) {
1418 ast_json_unref(to_json);
1419 return NULL;
1420 }
1421
1422 return to_json;
1423}
1424
1426 struct stasis_message *message,
1427 const struct stasis_message_sanitizer *sanitize)
1428{
1429 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1430 struct ast_json *blob = channel_blob->blob;
1431 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1432 const char *direction =
1433 ast_json_string_get(ast_json_object_get(blob, "direction"));
1434 const char *digit =
1436 long duration_ms =
1437 ast_json_integer_get(ast_json_object_get(blob, "duration_ms"));
1438 const struct timeval *tv = stasis_message_timestamp(message);
1439 struct ast_json *json_channel;
1440
1441 /* Only present received DTMF end events as JSON */
1442 if (strcasecmp("Received", direction) != 0) {
1443 return NULL;
1444 }
1445
1446 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1447 if (!json_channel) {
1448 return NULL;
1449 }
1450
1451 return ast_json_pack("{s: s, s: o, s: s, s: I, s: o}",
1452 "type", "ChannelDtmfReceived",
1453 "timestamp", ast_json_timeval(*tv, NULL),
1454 "digit", digit,
1455 "duration_ms", (ast_json_int_t)duration_ms,
1456 "channel", json_channel);
1457}
1458
1460 struct stasis_message *message,
1461 const struct stasis_message_sanitizer *sanitize)
1462{
1463 return channel_blob_to_json(message, "ChannelVarset", sanitize);
1464}
1465
1467 struct stasis_message *message,
1468 const struct stasis_message_sanitizer *sanitize)
1469{
1470 return channel_blob_to_json(message, "ChannelHangupRequest", sanitize);
1471}
1472
1473static struct ast_json *dial_to_json(
1474 struct stasis_message *message,
1475 const struct stasis_message_sanitizer *sanitize)
1476{
1478 struct ast_json *blob = ast_multi_channel_blob_get_json(payload);
1479 const char *dialstatus =
1480 ast_json_string_get(ast_json_object_get(blob, "dialstatus"));
1481 const char *forward =
1482 ast_json_string_get(ast_json_object_get(blob, "forward"));
1483 const char *dialstring =
1484 ast_json_string_get(ast_json_object_get(blob, "dialstring"));
1485 struct ast_json *caller_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "caller"), sanitize);
1486 struct ast_json *peer_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "peer"), sanitize);
1487 struct ast_json *forwarded_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "forwarded"), sanitize);
1488 struct ast_json *json;
1489 const struct timeval *tv = stasis_message_timestamp(message);
1490 int res = 0;
1491
1492 json = ast_json_pack("{s: s, s: o, s: s, s: s, s: s}",
1493 "type", "Dial",
1494 "timestamp", ast_json_timeval(*tv, NULL),
1495 "dialstatus", dialstatus,
1496 "forward", forward,
1497 "dialstring", dialstring);
1498 if (!json) {
1499 ast_json_unref(caller_json);
1500 ast_json_unref(peer_json);
1501 ast_json_unref(forwarded_json);
1502 return NULL;
1503 }
1504
1505 if (caller_json) {
1506 res |= ast_json_object_set(json, "caller", caller_json);
1507 }
1508 if (peer_json) {
1509 res |= ast_json_object_set(json, "peer", peer_json);
1510 }
1511 if (forwarded_json) {
1512 res |= ast_json_object_set(json, "forwarded", forwarded_json);
1513 }
1514
1515 if (res) {
1516 ast_json_unref(json);
1517 return NULL;
1518 }
1519
1520 return json;
1521}
1522
1524{
1525 struct ast_str *channel_string;
1526 struct ast_channel_blob *obj = stasis_message_data(msg);
1527 struct ast_manager_event_blob *blob;
1528
1529 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1530 if (!channel_string) {
1531 return NULL;
1532 }
1533
1534 blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStart",
1535 "%s", ast_str_buffer(channel_string));
1536 ast_free(channel_string);
1537
1538 return blob;
1539}
1540
1542 const struct stasis_message_sanitizer *sanitize)
1543{
1544 return channel_blob_to_json(message, "ChannelTalkingStarted", sanitize);
1545}
1546
1548{
1549 struct ast_str *channel_string;
1550 struct ast_channel_blob *obj = stasis_message_data(msg);
1551 int duration = ast_json_integer_get(ast_json_object_get(obj->blob, "duration"));
1552 struct ast_manager_event_blob *blob;
1553
1554 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
1555 if (!channel_string) {
1556 return NULL;
1557 }
1558
1559 blob = ast_manager_event_blob_create(EVENT_FLAG_CALL, "ChannelTalkingStop",
1560 "%s"
1561 "Duration: %d\r\n",
1562 ast_str_buffer(channel_string),
1563 duration);
1564 ast_free(channel_string);
1565
1566 return blob;
1567}
1568
1570 const struct stasis_message_sanitizer *sanitize)
1571{
1572 return channel_blob_to_json(message, "ChannelTalkingFinished", sanitize);
1573}
1574
1576 const struct stasis_message_sanitizer *sanitize)
1577{
1578 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1579 struct ast_json *blob = channel_blob->blob;
1580 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1581 const char *musicclass = ast_json_string_get(ast_json_object_get(blob, "musicclass"));
1582 const struct timeval *tv = stasis_message_timestamp(message);
1583 struct ast_json *json_channel;
1584
1585 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1586 if (!json_channel) {
1587 return NULL;
1588 }
1589
1590 return ast_json_pack("{s: s, s: o, s: s, s: o}",
1591 "type", "ChannelHold",
1592 "timestamp", ast_json_timeval(*tv, NULL),
1593 "musicclass", S_OR(musicclass, "N/A"),
1594 "channel", json_channel);
1595}
1596
1598 const struct stasis_message_sanitizer *sanitize)
1599{
1600 struct ast_channel_blob *channel_blob = stasis_message_data(message);
1601 struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
1602 const struct timeval *tv = stasis_message_timestamp(message);
1603 struct ast_json *json_channel;
1604
1605 json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
1606 if (!json_channel) {
1607 return NULL;
1608 }
1609
1610 return ast_json_pack("{s: s, s: o, s: o}",
1611 "type", "ChannelUnhold",
1612 "timestamp", ast_json_timeval(*tv, NULL),
1613 "channel", json_channel);
1614}
1615
1616/*!
1617 * @{ \brief Define channel message types.
1618 */
1621 .to_json = dial_to_json,
1622 );
1625 .to_json = varset_to_json,
1626 );
1628 .to_json = hangup_request_to_json,
1629 );
1633 .to_json = dtmf_end_to_json,
1634 );
1636 .to_json = hold_to_json,
1637 );
1639 .to_json = unhold_to_json,
1640 );
1654 );
1657 );
1660 .to_json = talking_start_to_json,
1661 );
1664 .to_json = talking_stop_to_json,
1665 );
1666
1667/*! @} */
1668
1670{
1677
1702}
1703
1705{
1706 int res = 0;
1707
1709
1710 channel_topic_all = stasis_topic_create("channel:all");
1711 if (!channel_topic_all) {
1712 return -1;
1713 }
1714
1718 if (!channel_cache) {
1719 return -1;
1720 }
1721
1725 if (!channel_cache_by_name) {
1726 return -1;
1727 }
1728
1753
1754 return res;
1755}
1756
1757/*!
1758 * \internal
1759 * \brief A list element for the dial_masquerade_datastore -- stores data about a dialed peer
1760 */
1762 /*! Called party channel. */
1764 /*! Dialstring used to call the peer. */
1766 /*! Next entry in the list. */
1768};
1769
1770static void dial_target_free(struct dial_target *doomed)
1771{
1772 if (!doomed) {
1773 return;
1774 }
1775 ast_free(doomed->dialstring);
1776 ast_channel_cleanup(doomed->peer);
1777 ast_free(doomed);
1778}
1779
1780/*!
1781 * \internal
1782 * \brief Datastore used for advancing dial state in the case of a masquerade
1783 * against a channel in the process of dialing.
1784 */
1786 /*! Calling party channel. */
1788 /*! List of called peers. */
1790};
1791
1793{
1794 struct dial_target *cur;
1795
1796 while ((cur = AST_LIST_REMOVE_HEAD(&masq_data->dialed_peers, list))) {
1797 dial_target_free(cur);
1798 }
1799}
1800
1802{
1803 struct dial_target *cur;
1804
1805 ao2_lock(masq_data);
1806 if (masq_data->caller == chan) {
1808 } else {
1810 if (cur->peer == chan) {
1812 dial_target_free(cur);
1813 break;
1814 }
1815 }
1817 }
1818 ao2_unlock(masq_data);
1819}
1820
1821static void dial_masquerade_datastore_dtor(void *vdoomed)
1822{
1824}
1825
1827{
1828 struct dial_masquerade_datastore *masq_data;
1829
1830 masq_data = ao2_alloc(sizeof(struct dial_masquerade_datastore),
1832 if (!masq_data) {
1833 return NULL;
1834 }
1836 return masq_data;
1837}
1838
1839/*!
1840 * \internal
1841 * \brief Datastore destructor for dial_masquerade_datastore
1842 */
1844{
1845 ao2_ref(data, -1);
1846}
1847
1848/*!
1849 * \internal
1850 * \brief Datastore destructor for dial_masquerade_datastore
1851 */
1853{
1855 ao2_ref(data, -1);
1856}
1857
1858static struct ast_datastore *dial_masquerade_datastore_find(struct ast_channel *chan);
1859
1860static void dial_masquerade_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1861{
1862 struct dial_masquerade_datastore *masq_data = data;
1863 struct dial_target *cur;
1864 struct ast_datastore *datastore;
1865
1866 ao2_lock(masq_data);
1867 if (!masq_data->caller) {
1868 /* Nothing to do but remove the datastore */
1869 } else if (masq_data->caller == old_chan) {
1870 /* The caller channel is being masqueraded out. */
1871 ast_debug(1, "Caller channel %s being masqueraded out to %s (is_empty:%d)\n",
1872 ast_channel_name(new_chan), ast_channel_name(old_chan),
1873 AST_LIST_EMPTY(&masq_data->dialed_peers));
1874 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
1876 cur->dialstring, "NOANSWER", NULL);
1878 cur->dialstring, NULL, NULL);
1879 }
1881 } else {
1882 /* One of the peer channels is being masqueraded out. */
1883 AST_LIST_TRAVERSE_SAFE_BEGIN(&masq_data->dialed_peers, cur, list) {
1884 if (cur->peer == old_chan) {
1885 ast_debug(1, "Peer channel %s being masqueraded out to %s\n",
1886 ast_channel_name(new_chan), ast_channel_name(old_chan));
1887 ast_channel_publish_dial_internal(masq_data->caller, new_chan, NULL,
1888 cur->dialstring, "CANCEL", NULL);
1889 ast_channel_publish_dial_internal(masq_data->caller, old_chan, NULL,
1890 cur->dialstring, NULL, NULL);
1891
1893 dial_target_free(cur);
1894 break;
1895 }
1896 }
1898 }
1899 ao2_unlock(masq_data);
1900
1901 /* Remove the datastore from the channel. */
1902 datastore = dial_masquerade_datastore_find(old_chan);
1903 if (!datastore) {
1904 return;
1905 }
1906 ast_channel_datastore_remove(old_chan, datastore);
1907 ast_datastore_free(datastore);
1908}
1909
1910/*!
1911 * \internal
1912 * \brief Primary purpose for dial_masquerade_datastore, publishes
1913 * the channel dial event needed to set the incoming channel into the
1914 * dial state during a masquerade.
1915 * \param data pointer to the dial_masquerade_datastore
1916 * \param old_chan Channel being replaced
1917 * \param new_chan Channel being pushed to dial mode
1918 */
1919static void dial_masquerade_breakdown(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
1920{
1921 struct dial_masquerade_datastore *masq_data = data;
1922 struct dial_target *cur;
1923
1924 ao2_lock(masq_data);
1925
1926 if (!masq_data->caller) {
1927 ao2_unlock(masq_data);
1928 return;
1929 }
1930
1931 if (masq_data->caller == new_chan) {
1932 /*
1933 * The caller channel is being masqueraded into.
1934 * The masquerade is likely because of a blonde transfer.
1935 */
1936 ast_debug(1, "Caller channel %s being masqueraded into by %s (is_empty:%d)\n",
1937 ast_channel_name(old_chan), ast_channel_name(new_chan),
1938 AST_LIST_EMPTY(&masq_data->dialed_peers));
1939 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
1941 cur->dialstring, "NOANSWER", NULL);
1943 cur->dialstring, NULL, NULL);
1944 }
1945
1946 ao2_unlock(masq_data);
1947 return;
1948 }
1949
1950 /*
1951 * One of the peer channels is being masqueraded into.
1952 * The masquerade is likely because of a call pickup.
1953 */
1954 AST_LIST_TRAVERSE(&masq_data->dialed_peers, cur, list) {
1955 if (cur->peer == new_chan) {
1956 ast_debug(1, "Peer channel %s being masqueraded into by %s\n",
1957 ast_channel_name(old_chan), ast_channel_name(new_chan));
1958 ast_channel_publish_dial_internal(masq_data->caller, old_chan, NULL,
1959 cur->dialstring, "CANCEL", NULL);
1960 ast_channel_publish_dial_internal(masq_data->caller, new_chan, NULL,
1961 cur->dialstring, NULL, NULL);
1962 break;
1963 }
1964 }
1965
1966 ao2_unlock(masq_data);
1967}
1968
1970 .type = "stasis-chan-dial-masq",
1972 .chan_fixup = dial_masquerade_fixup,
1973 .chan_breakdown = dial_masquerade_breakdown,
1974};
1975
1977 .type = "stasis-chan-dial-masq",
1979 .chan_fixup = dial_masquerade_fixup,
1980 .chan_breakdown = dial_masquerade_breakdown,
1981};
1982
1983/*!
1984 * \internal
1985 * \brief Find the dial masquerade datastore on the given channel.
1986 *
1987 * \param chan Channel a datastore data is wanted from
1988 *
1989 * \return A pointer to the datastore if it exists.
1990 */
1992{
1993 struct ast_datastore *datastore;
1994
1996 if (!datastore) {
1998 }
1999
2000 return datastore;
2001}
2002
2003/*!
2004 * \internal
2005 * \brief Add the dial masquerade datastore to a channel.
2006 *
2007 * \param chan Channel to setup dial masquerade datastore on.
2008 * \param masq_data NULL to setup caller datastore otherwise steals the ref on success.
2009 *
2010 * \retval masq_data given or created on success.
2011 * (A ref is not returned but can be obtained before chan is unlocked.)
2012 * \retval NULL on error. masq_data ref is not stolen.
2013 */
2015 struct ast_channel *chan, struct dial_masquerade_datastore *masq_data)
2016{
2017 struct ast_datastore *datastore;
2018
2020 if (!datastore) {
2021 return NULL;
2022 }
2023
2024 if (!masq_data) {
2025 masq_data = dial_masquerade_datastore_alloc();
2026 if (!masq_data) {
2027 ast_datastore_free(datastore);
2028 return NULL;
2029 }
2030 masq_data->caller = chan;
2031 }
2032
2033 datastore->data = masq_data;
2034 ast_channel_datastore_add(chan, datastore);
2035
2036 return masq_data;
2037}
2038
2039static int set_dial_masquerade(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring)
2040{
2041 struct ast_datastore *datastore;
2042 struct dial_masquerade_datastore *masq_data;
2043 struct dial_target *target;
2044
2045 /* Find or create caller datastore */
2046 datastore = dial_masquerade_datastore_find(caller);
2047 if (!datastore) {
2048 masq_data = dial_masquerade_datastore_add(caller, NULL);
2049 } else {
2050 masq_data = datastore->data;
2051 }
2052 if (!masq_data) {
2053 return -1;
2054 }
2055 ao2_ref(masq_data, +1);
2056
2057 /*
2058 * Someone likely forgot to do an ast_channel_publish_dial()
2059 * or ast_channel_publish_dial_forward() with a final dial
2060 * status on the channel.
2061 */
2062 ast_assert(masq_data->caller == caller);
2063
2064 /* Create peer target to put into datastore */
2065 target = ast_calloc(1, sizeof(*target));
2066 if (!target) {
2067 ao2_ref(masq_data, -1);
2068 return -1;
2069 }
2070 if (dialstring) {
2071 target->dialstring = ast_strdup(dialstring);
2072 if (!target->dialstring) {
2073 ast_free(target);
2074 ao2_ref(masq_data, -1);
2075 return -1;
2076 }
2077 }
2078 target->peer = ast_channel_ref(peer);
2079
2080 /* Put peer target into datastore */
2081 ao2_lock(masq_data);
2083 AST_LIST_INSERT_HEAD(&masq_data->dialed_peers, target, list);
2084 ao2_unlock(masq_data);
2085
2087 if (datastore) {
2088 if (datastore->data == masq_data) {
2089 /*
2090 * Peer already had the datastore for this dial masquerade.
2091 * This was a redundant peer dial masquerade setup.
2092 */
2093 ao2_ref(masq_data, -1);
2094 return 0;
2095 }
2096
2097 /* Something is wrong. Try to fix if the assert doesn't abort. */
2098 ast_assert(0);
2099
2100 /* Remove the stale dial masquerade datastore */
2103 ast_datastore_free(datastore);
2104 }
2105
2106 /* Create the peer dial masquerade datastore */
2107 if (dial_masquerade_datastore_add(peer, masq_data)) {
2108 /* Success */
2109 return 0;
2110 }
2111
2112 /* Failed to create the peer datastore */
2114 ao2_ref(masq_data, -1);
2115 return -1;
2116}
2117
2119{
2120 struct ast_datastore *datastore;
2121 struct dial_masquerade_datastore *masq_data;
2122
2123 datastore = dial_masquerade_datastore_find(peer);
2124 if (!datastore) {
2125 return;
2126 }
2127
2128 masq_data = datastore->data;
2129 if (masq_data) {
2131 }
2132
2133 ast_channel_datastore_remove(peer, datastore);
2134 ast_datastore_free(datastore);
2135}
2136
2138{
2139 struct ast_datastore *datastore;
2140 struct dial_masquerade_datastore *masq_data;
2141
2143 if (!datastore) {
2144 return;
2145 }
2146
2147 masq_data = datastore->data;
2148 if (!masq_data || !AST_LIST_EMPTY(&masq_data->dialed_peers)) {
2149 return;
2150 }
2151
2153
2155 ast_datastore_free(datastore);
2156}
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_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition: astobj2.h:1600
#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_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ 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:327
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:476
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:7982
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:2385
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2394
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:1821
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:2922
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:7987
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:2947
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:2924
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:155
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:10533
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:7854
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:1050
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:2969
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
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:2399
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_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:10440
#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:617
#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:1511
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 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 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:386
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