2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3 * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
19 * The Initial Developer of the Original Code is
20 * Anthony Minessale II <anthm@freeswitch.org>
21 * Portions created by the Initial Developer are Copyright (C)
22 * the Initial Developer. All Rights Reserved.
26 * Anthony Minessale II <anthm@freeswitch.org>
27 * Michael Jerris <mike@jerris.com>
28 * Paul D. Tinsley <pdt at jackhammer.org>
29 * William King <william.king@quentustech.com>
30 * Raymond Chandler <intralanman@freeswitch.org>
32 * switch_event.c -- Event System
37 #include "private/switch_core_pvt.h"
38 #include <switch_event.h>
43 //#define SWITCH_EVENT_RECYCLE
44 #define DISPATCH_QUEUE_LEN 10000
45 //#define DEBUG_DISPATCH_QUEUES
47 /*! \brief A node to store binded events */
48 struct switch_event_node
{
49 /*! the id of the node */
51 /*! the event id enumeration to bind to */
52 switch_event_types_t event_id
;
53 /*! the event subclass to bind to for custom events */
55 /*! a callback function to execute when the event is triggered */
56 switch_event_callback_t callback
;
59 struct switch_event_node
*next
;
62 /*! \brief A registered custom event subclass */
63 struct switch_event_subclass
{
64 /*! the owner of the subclass */
66 /*! the subclass name */
68 /*! the subclass was reserved by a listener so it's ok for a module to reserve it still */
74 switch_event_channel_id_t ID
;
75 switch_thread_rwlock_t
*rwlock
;
77 switch_hash_t
*perm_hash
;
78 switch_hash_t
*lahash
;
79 switch_mutex_t
*lamutex
;
80 } event_channel_manager
;
82 #define MAX_DISPATCH_VAL 64
83 static unsigned int MAX_DISPATCH
= MAX_DISPATCH_VAL
;
84 static unsigned int SOFT_MAX_DISPATCH
= 0;
85 static char guess_ip_v4
[80] = "";
86 static char guess_ip_v6
[80] = "";
87 static switch_event_node_t
*EVENT_NODES
[SWITCH_EVENT_ALL
+ 1] = { NULL
};
88 static switch_thread_rwlock_t
*RWLOCK
= NULL
;
89 static switch_mutex_t
*BLOCK
= NULL
;
90 static switch_mutex_t
*POOL_LOCK
= NULL
;
91 static switch_memory_pool_t
*RUNTIME_POOL
= NULL
;
92 static switch_memory_pool_t
*THRUNTIME_POOL
= NULL
;
93 static switch_thread_t
*EVENT_DISPATCH_QUEUE_THREADS
[MAX_DISPATCH_VAL
] = { 0 };
94 static uint8_t EVENT_DISPATCH_QUEUE_RUNNING
[MAX_DISPATCH_VAL
] = { 0 };
95 static switch_queue_t
*EVENT_DISPATCH_QUEUE
= NULL
;
96 static switch_queue_t
*EVENT_CHANNEL_DISPATCH_QUEUE
= NULL
;
97 static switch_mutex_t
*EVENT_QUEUE_MUTEX
= NULL
;
98 static switch_mutex_t
*CUSTOM_HASH_MUTEX
= NULL
;
99 static switch_hash_t
*CUSTOM_HASH
= NULL
;
100 static int THREAD_COUNT
= 0;
101 static int DISPATCH_THREAD_COUNT
= 0;
102 static int EVENT_CHANNEL_DISPATCH_THREAD_COUNT
= 0;
103 static int EVENT_CHANNEL_DISPATCH_THREAD_STARTING
= 0;
104 static int SYSTEM_RUNNING
= 0;
105 static uint64_t EVENT_SEQUENCE_NR
= 0;
106 #ifdef SWITCH_EVENT_RECYCLE
107 static switch_queue_t
*EVENT_RECYCLE_QUEUE
= NULL
;
108 static switch_queue_t
*EVENT_HEADER_RECYCLE_QUEUE
= NULL
;
111 static void unsub_all_switch_event_channel(void);
113 static char *my_dup(const char *s
)
115 size_t len
= strlen(s
) + 1;
116 void *new = malloc(len
);
119 return (char *) memcpy(new, s
, len
);
123 #define ALLOC(size) malloc(size)
126 #define DUP(str) my_dup(str)
129 #define FREE(ptr) switch_safe_free(ptr)
132 /* make sure this is synced with the switch_event_types_t enum in switch_types.h
133 also never put any new ones before EVENT_ALL
135 static char *EVENT_NAMES
[] = {
144 "CHANNEL_HANGUP_COMPLETE",
146 "CHANNEL_EXECUTE_COMPLETE",
152 "CHANNEL_PROGRESS_MEDIA",
156 "CHANNEL_APPLICATION",
195 "PHONE_FEATURE_SUBSCRIBE",
203 "CLIENT_DISCONNECTED",
204 "SERVER_DISCONNECTED",
219 "CONFERENCE_DATA_QUERY",
229 static int switch_events_match(switch_event_t
*event
, switch_event_node_t
*node
)
233 if (node
->event_id
== SWITCH_EVENT_ALL
) {
236 if (!node
->subclass_name
) {
241 if (match
|| event
->event_id
== node
->event_id
) {
243 if (event
->subclass_name
&& node
->subclass_name
) {
244 if (!strncasecmp(node
->subclass_name
, "file:", 5)) {
246 if ((file_header
= switch_event_get_header(event
, "file")) != 0) {
247 match
= !strcmp(node
->subclass_name
+ 5, file_header
) ? 1 : 0;
249 } else if (!strncasecmp(node
->subclass_name
, "func:", 5)) {
251 if ((func_header
= switch_event_get_header(event
, "function")) != 0) {
252 match
= !strcmp(node
->subclass_name
+ 5, func_header
) ? 1 : 0;
254 } else if (event
->subclass_name
&& node
->subclass_name
) {
255 match
= !strcmp(event
->subclass_name
, node
->subclass_name
) ? 1 : 0;
257 } else if ((event
->subclass_name
&& !node
->subclass_name
) || (!event
->subclass_name
&& !node
->subclass_name
)) {
268 static void *SWITCH_THREAD_FUNC
switch_event_deliver_thread(switch_thread_t
*thread
, void *obj
)
270 switch_event_t
*event
= (switch_event_t
*) obj
;
272 switch_event_deliver(&event
);
277 static void switch_event_deliver_thread_pool(switch_event_t
**event
)
279 switch_thread_data_t
*td
;
281 td
= malloc(sizeof(*td
));
285 td
->func
= switch_event_deliver_thread
;
291 switch_thread_pool_launch_thread(&td
);
295 static void *SWITCH_THREAD_FUNC
switch_event_dispatch_thread(switch_thread_t
*thread
, void *obj
)
297 switch_queue_t
*queue
= (switch_queue_t
*) obj
;
300 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
302 DISPATCH_THREAD_COUNT
++;
304 for (my_id
= 0; my_id
< MAX_DISPATCH_VAL
; my_id
++) {
305 if (EVENT_DISPATCH_QUEUE_THREADS
[my_id
] == thread
) {
310 if ( my_id
>= MAX_DISPATCH_VAL
) {
311 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
315 EVENT_DISPATCH_QUEUE_RUNNING
[my_id
] = 1;
316 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
321 switch_event_t
*event
= NULL
;
323 if (!SYSTEM_RUNNING
) {
327 if (switch_queue_pop(queue
, &pop
) != SWITCH_STATUS_SUCCESS
) {
335 event
= (switch_event_t
*) pop
;
336 switch_event_deliver(&event
);
341 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
342 EVENT_DISPATCH_QUEUE_RUNNING
[my_id
] = 0;
344 DISPATCH_THREAD_COUNT
--;
345 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
347 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Dispatch Thread %d Ended.\n", my_id
);
352 static int PENDING
= 0;
354 static switch_status_t
switch_event_queue_dispatch_event(switch_event_t
**eventp
)
357 switch_event_t
*event
= *eventp
;
359 if (!SYSTEM_RUNNING
) {
360 return SWITCH_STATUS_FALSE
;
366 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
368 if (!PENDING
&& switch_queue_size(EVENT_DISPATCH_QUEUE
) > (unsigned int)(DISPATCH_QUEUE_LEN
* DISPATCH_THREAD_COUNT
)) {
369 if (SOFT_MAX_DISPATCH
+ 1 < MAX_DISPATCH
) {
375 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
378 if (SOFT_MAX_DISPATCH
+ 1 < MAX_DISPATCH
) {
379 switch_event_launch_dispatch_threads(SOFT_MAX_DISPATCH
+ 1);
382 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
384 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
388 switch_queue_push(EVENT_DISPATCH_QUEUE
, event
);
393 return SWITCH_STATUS_SUCCESS
;
396 SWITCH_DECLARE(void) switch_event_deliver(switch_event_t
**event
)
398 switch_event_types_t e
;
399 switch_event_node_t
*node
;
401 if (SYSTEM_RUNNING
) {
402 switch_thread_rwlock_rdlock(RWLOCK
);
403 for (e
= (*event
)->event_id
;; e
= SWITCH_EVENT_ALL
) {
404 for (node
= EVENT_NODES
[e
]; node
; node
= node
->next
) {
405 if (switch_events_match(*event
, node
)) {
406 (*event
)->bind_user_data
= node
->user_data
;
407 node
->callback(*event
);
411 if (e
== SWITCH_EVENT_ALL
) {
415 switch_thread_rwlock_unlock(RWLOCK
);
418 switch_event_destroy(event
);
421 SWITCH_DECLARE(switch_status_t
) switch_event_running(void)
423 return SYSTEM_RUNNING
? SWITCH_STATUS_SUCCESS
: SWITCH_STATUS_FALSE
;
426 SWITCH_DECLARE(const char *) switch_event_name(switch_event_types_t event
)
428 switch_assert(BLOCK
!= NULL
);
429 switch_assert(RUNTIME_POOL
!= NULL
);
431 return EVENT_NAMES
[event
];
434 SWITCH_DECLARE(switch_status_t
) switch_name_event(const char *name
, switch_event_types_t
*type
)
436 switch_event_types_t x
;
437 switch_assert(BLOCK
!= NULL
);
438 switch_assert(RUNTIME_POOL
!= NULL
);
440 for (x
= 0; x
<= SWITCH_EVENT_ALL
; x
++) {
441 if ((strlen(name
) > 13 && !strcasecmp(name
+ 13, EVENT_NAMES
[x
])) || !strcasecmp(name
, EVENT_NAMES
[x
])) {
443 return SWITCH_STATUS_SUCCESS
;
447 return SWITCH_STATUS_FALSE
;
450 SWITCH_DECLARE(switch_status_t
) switch_event_free_subclass_detailed(const char *owner
, const char *subclass_name
)
452 switch_event_subclass_t
*subclass
;
453 switch_status_t status
= SWITCH_STATUS_FALSE
;
455 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
457 switch_assert(RUNTIME_POOL
!= NULL
);
458 switch_assert(CUSTOM_HASH
!= NULL
);
460 if ((subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
))) {
461 if (!strcmp(owner
, subclass
->owner
)) {
462 switch_thread_rwlock_wrlock(RWLOCK
);
463 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Subclass reservation deleted for %s:%s\n", owner
, subclass_name
);
464 switch_core_hash_delete(CUSTOM_HASH
, subclass_name
);
465 FREE(subclass
->owner
);
466 FREE(subclass
->name
);
468 status
= SWITCH_STATUS_SUCCESS
;
469 switch_thread_rwlock_unlock(RWLOCK
);
471 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Subclass reservation %s inuse by listeners, detaching..\n", subclass_name
);
476 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
481 SWITCH_DECLARE(switch_status_t
) switch_event_reserve_subclass_detailed(const char *owner
, const char *subclass_name
)
483 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
484 switch_event_subclass_t
*subclass
;
486 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
488 switch_assert(RUNTIME_POOL
!= NULL
);
489 switch_assert(CUSTOM_HASH
!= NULL
);
491 if ((subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
))) {
492 /* a listener reserved it for us, now we can lock it so nobody else can have it */
493 if (subclass
->bind
) {
495 switch_goto_status(SWITCH_STATUS_SUCCESS
, end
);
497 switch_goto_status(SWITCH_STATUS_INUSE
, end
);
500 switch_zmalloc(subclass
, sizeof(*subclass
));
502 subclass
->owner
= DUP(owner
);
503 subclass
->name
= DUP(subclass_name
);
505 switch_core_hash_insert(CUSTOM_HASH
, subclass
->name
, subclass
);
509 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
514 SWITCH_DECLARE(void) switch_core_memory_reclaim_events(void)
516 #ifdef SWITCH_EVENT_RECYCLE
520 size
= switch_queue_size(EVENT_RECYCLE_QUEUE
);
522 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Returning %d recycled event(s) %d bytes\n", size
, (int) sizeof(switch_event_t
) * size
);
523 size
= switch_queue_size(EVENT_HEADER_RECYCLE_QUEUE
);
524 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Returning %d recycled event header(s) %d bytes\n",
525 size
, (int) sizeof(switch_event_header_t
) * size
);
527 while (switch_queue_trypop(EVENT_HEADER_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
530 while (switch_queue_trypop(EVENT_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
539 SWITCH_DECLARE(switch_status_t
) switch_event_shutdown(void)
543 switch_hash_index_t
*hi
;
547 if (switch_core_test_flag(SCF_MINIMAL
)) {
548 return SWITCH_STATUS_SUCCESS
;
551 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
553 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
555 unsub_all_switch_event_channel();
557 if (EVENT_CHANNEL_DISPATCH_QUEUE
) {
558 switch_queue_trypush(EVENT_CHANNEL_DISPATCH_QUEUE
, NULL
);
559 switch_queue_interrupt_all(EVENT_CHANNEL_DISPATCH_QUEUE
);
562 if (runtime
.events_use_dispatch
) {
563 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Stopping dispatch queues\n");
565 for(x
= 0; x
< (uint32_t)DISPATCH_THREAD_COUNT
; x
++) {
566 switch_queue_trypush(EVENT_DISPATCH_QUEUE
, NULL
);
570 switch_queue_interrupt_all(EVENT_DISPATCH_QUEUE
);
572 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Stopping dispatch threads\n");
574 for(x
= 0; x
< (uint32_t)MAX_DISPATCH
; x
++) {
575 if (EVENT_DISPATCH_QUEUE_THREADS
[x
]) {
577 switch_thread_join(&st
, EVENT_DISPATCH_QUEUE_THREADS
[x
]);
583 while (x
< 100 && THREAD_COUNT
) {
584 switch_yield(100000);
585 if (THREAD_COUNT
== last
) {
591 if (runtime
.events_use_dispatch
) {
593 switch_event_t
*event
= NULL
;
595 while (switch_queue_trypop(EVENT_DISPATCH_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
596 event
= (switch_event_t
*) pop
;
597 switch_event_destroy(&event
);
601 for (hi
= switch_core_hash_first(CUSTOM_HASH
); hi
; hi
= switch_core_hash_next(&hi
)) {
602 switch_event_subclass_t
*subclass
;
603 switch_core_hash_this(hi
, &var
, NULL
, &val
);
604 if ((subclass
= (switch_event_subclass_t
*) val
)) {
605 FREE(subclass
->name
);
606 FREE(subclass
->owner
);
611 switch_core_hash_destroy(&event_channel_manager
.lahash
);
612 switch_core_hash_destroy(&event_channel_manager
.hash
);
613 switch_core_hash_destroy(&event_channel_manager
.perm_hash
);
615 switch_core_hash_destroy(&CUSTOM_HASH
);
616 switch_core_memory_reclaim_events();
618 return SWITCH_STATUS_SUCCESS
;
621 static void check_dispatch(void)
623 if (!EVENT_DISPATCH_QUEUE
) {
624 switch_mutex_lock(BLOCK
);
626 if (!EVENT_DISPATCH_QUEUE
) {
627 switch_queue_create(&EVENT_DISPATCH_QUEUE
, DISPATCH_QUEUE_LEN
* MAX_DISPATCH
, THRUNTIME_POOL
);
628 switch_event_launch_dispatch_threads(1);
630 while (!THREAD_COUNT
) {
634 switch_mutex_unlock(BLOCK
);
640 SWITCH_DECLARE(void) switch_event_launch_dispatch_threads(uint32_t max
)
642 switch_threadattr_t
*thd_attr
;
645 uint32_t sanity
= 200;
647 switch_memory_pool_t
*pool
= RUNTIME_POOL
;
651 if (max
> MAX_DISPATCH
) {
655 if (max
< SOFT_MAX_DISPATCH
) {
659 for (index
= SOFT_MAX_DISPATCH
; index
< max
&& index
< MAX_DISPATCH
; index
++) {
660 if (EVENT_DISPATCH_QUEUE_THREADS
[index
]) {
664 switch_threadattr_create(&thd_attr
, pool
);
665 switch_threadattr_stacksize_set(thd_attr
, SWITCH_THREAD_STACKSIZE
);
666 switch_threadattr_priority_set(thd_attr
, SWITCH_PRI_REALTIME
);
667 switch_thread_create(&EVENT_DISPATCH_QUEUE_THREADS
[index
], thd_attr
, switch_event_dispatch_thread
, EVENT_DISPATCH_QUEUE
, pool
);
668 while(--sanity
&& !EVENT_DISPATCH_QUEUE_RUNNING
[index
]) switch_yield(10000);
671 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "Create event dispatch thread %d\n", index
);
673 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "Create additional event dispatch thread %d\n", index
);
678 SOFT_MAX_DISPATCH
= index
;
681 SWITCH_DECLARE(switch_status_t
) switch_event_init(switch_memory_pool_t
*pool
)
684 /* don't need any more dispatch threads than we have CPU's*/
685 MAX_DISPATCH
= (switch_core_cpu_count() / 2) + 1;
686 if (MAX_DISPATCH
< 2) {
690 switch_assert(pool
!= NULL
);
691 THRUNTIME_POOL
= RUNTIME_POOL
= pool
;
692 switch_thread_rwlock_create(&RWLOCK
, RUNTIME_POOL
);
693 switch_mutex_init(&BLOCK
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
694 switch_mutex_init(&POOL_LOCK
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
695 switch_mutex_init(&EVENT_QUEUE_MUTEX
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
696 switch_mutex_init(&CUSTOM_HASH_MUTEX
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
697 switch_core_hash_init(&CUSTOM_HASH
);
699 if (switch_core_test_flag(SCF_MINIMAL
)) {
700 return SWITCH_STATUS_SUCCESS
;
703 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_INFO
, "Activate Eventing Engine.\n");
705 switch_core_hash_init(&event_channel_manager
.lahash
);
706 switch_mutex_init(&event_channel_manager
.lamutex
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
708 switch_thread_rwlock_create(&event_channel_manager
.rwlock
, RUNTIME_POOL
);
709 switch_core_hash_init(&event_channel_manager
.hash
);
710 switch_core_hash_init(&event_channel_manager
.perm_hash
);
711 event_channel_manager
.ID
= 1;
713 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
715 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
717 //switch_threadattr_create(&thd_attr, pool);
718 switch_find_local_ip(guess_ip_v4
, sizeof(guess_ip_v4
), NULL
, AF_INET
);
719 switch_find_local_ip(guess_ip_v6
, sizeof(guess_ip_v6
), NULL
, AF_INET6
);
722 #ifdef SWITCH_EVENT_RECYCLE
723 switch_queue_create(&EVENT_RECYCLE_QUEUE
, 250000, THRUNTIME_POOL
);
724 switch_queue_create(&EVENT_HEADER_RECYCLE_QUEUE
, 250000, THRUNTIME_POOL
);
729 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
731 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
733 return SWITCH_STATUS_SUCCESS
;
736 SWITCH_DECLARE(switch_status_t
) switch_event_create_subclass_detailed(const char *file
, const char *func
, int line
,
737 switch_event_t
**event
, switch_event_types_t event_id
, const char *subclass_name
)
739 #ifdef SWITCH_EVENT_RECYCLE
745 if ((event_id
!= SWITCH_EVENT_CLONE
&& event_id
!= SWITCH_EVENT_CUSTOM
) && subclass_name
) {
746 return SWITCH_STATUS_GENERR
;
748 #ifdef SWITCH_EVENT_RECYCLE
749 if (EVENT_RECYCLE_QUEUE
&& switch_queue_trypop(EVENT_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
750 *event
= (switch_event_t
*) pop
;
753 *event
= ALLOC(sizeof(switch_event_t
));
754 switch_assert(*event
);
755 #ifdef SWITCH_EVENT_RECYCLE
759 memset(*event
, 0, sizeof(switch_event_t
));
761 if (event_id
== SWITCH_EVENT_REQUEST_PARAMS
|| event_id
== SWITCH_EVENT_CHANNEL_DATA
|| event_id
== SWITCH_EVENT_MESSAGE
) {
762 (*event
)->flags
|= EF_UNIQ_HEADERS
;
765 if (event_id
!= SWITCH_EVENT_CLONE
) {
766 (*event
)->event_id
= event_id
;
767 switch_event_prep_for_delivery_detailed(file
, func
, line
, *event
);
771 (*event
)->subclass_name
= DUP(subclass_name
);
772 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, "Event-Subclass", subclass_name
);
775 return SWITCH_STATUS_SUCCESS
;
778 SWITCH_DECLARE(switch_status_t
) switch_event_set_priority(switch_event_t
*event
, switch_priority_t priority
)
780 event
->priority
= priority
;
781 switch_event_add_header_string(event
, SWITCH_STACK_TOP
, "priority", switch_priority_name(priority
));
782 return SWITCH_STATUS_SUCCESS
;
785 SWITCH_DECLARE(switch_status_t
) switch_event_rename_header(switch_event_t
*event
, const char *header_name
, const char *new_header_name
)
787 switch_event_header_t
*hp
;
788 switch_ssize_t hlen
= -1;
789 unsigned long hash
= 0;
792 switch_assert(event
);
795 return SWITCH_STATUS_FALSE
;
798 hash
= switch_ci_hashfunc_default(header_name
, &hlen
);
800 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
801 if ((!hp
->hash
|| hash
== hp
->hash
) && !strcasecmp(hp
->name
, header_name
)) {
803 hp
->name
= DUP(new_header_name
);
805 hp
->hash
= switch_ci_hashfunc_default(hp
->name
, &hlen
);
810 return x
? SWITCH_STATUS_SUCCESS
: SWITCH_STATUS_FALSE
;
814 SWITCH_DECLARE(switch_event_header_t
*) switch_event_get_header_ptr(switch_event_t
*event
, const char *header_name
)
816 switch_event_header_t
*hp
;
817 switch_ssize_t hlen
= -1;
818 unsigned long hash
= 0;
820 switch_assert(event
);
825 hash
= switch_ci_hashfunc_default(header_name
, &hlen
);
827 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
828 if ((!hp
->hash
|| hash
== hp
->hash
) && !strcasecmp(hp
->name
, header_name
)) {
835 SWITCH_DECLARE(char *) switch_event_get_header_idx(switch_event_t
*event
, const char *header_name
, int idx
)
837 switch_event_header_t
*hp
;
839 if ((hp
= switch_event_get_header_ptr(event
, header_name
))) {
842 return hp
->array
[idx
];
849 } else if (!strcmp(header_name
, "_body")) {
856 SWITCH_DECLARE(char *) switch_event_get_body(switch_event_t
*event
)
858 return (event
? event
->body
: NULL
);
861 SWITCH_DECLARE(switch_status_t
) switch_event_del_header_val(switch_event_t
*event
, const char *header_name
, const char *val
)
863 switch_event_header_t
*hp
, *lp
= NULL
, *tp
;
864 switch_status_t status
= SWITCH_STATUS_FALSE
;
866 switch_ssize_t hlen
= -1;
867 unsigned long hash
= 0;
870 hash
= switch_ci_hashfunc_default(header_name
, &hlen
);
876 switch_assert(x
< 1000000);
878 if ((!hp
->hash
|| hash
== hp
->hash
) && !strcasecmp(header_name
, hp
->name
) && (zstr(val
) || !strcmp(hp
->value
, val
))) {
882 event
->headers
= hp
->next
;
884 if (hp
== event
->last_header
|| !hp
->next
) {
885 event
->last_header
= lp
;
892 for (i
= 0; i
< hp
->idx
; i
++) {
900 memset(hp
, 0, sizeof(*hp
));
901 #ifdef SWITCH_EVENT_RECYCLE
902 if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE
, hp
) != SWITCH_STATUS_SUCCESS
) {
908 status
= SWITCH_STATUS_SUCCESS
;
917 static switch_event_header_t
*new_header(const char *header_name
)
919 switch_event_header_t
*header
;
921 #ifdef SWITCH_EVENT_RECYCLE
923 if (EVENT_HEADER_RECYCLE_QUEUE
&& switch_queue_trypop(EVENT_HEADER_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
) {
924 header
= (switch_event_header_t
*) pop
;
927 header
= ALLOC(sizeof(*header
));
928 switch_assert(header
);
929 #ifdef SWITCH_EVENT_RECYCLE
933 memset(header
, 0, sizeof(*header
));
934 header
->name
= DUP(header_name
);
940 SWITCH_DECLARE(int) switch_event_add_array(switch_event_t
*event
, const char *var
, const char *val
)
949 if (strlen(val
) < 8) {
957 while((p
= strstr(p
, "|:"))) {
962 data
= strdup(val
+ 7);
964 len
= (sizeof(char *) * max
) + 1;
968 switch_assert(array
);
969 memset(array
, 0, len
);
971 switch_separate_string_string(data
, "|:", array
, max
);
973 for(i
= 0; i
< max
; i
++) {
974 switch_event_add_header_string(event
, SWITCH_STACK_PUSH
, var
, array
[i
]);
983 static switch_status_t
switch_event_base_add_header(switch_event_t
*event
, switch_stack_t stack
, const char *header_name
, char *data
)
985 switch_event_header_t
*header
= NULL
;
986 switch_ssize_t hlen
= -1;
987 int exists
= 0, fly
= 0;
990 char *real_header_name
= NULL
;
993 if (!strcmp(header_name
, "_body")) {
994 switch_event_set_body(event
, data
);
997 if ((index_ptr
= strchr(header_name
, '['))) {
999 index
= atoi(index_ptr
);
1000 real_header_name
= DUP(header_name
);
1001 if ((index_ptr
= strchr(real_header_name
, '['))) {
1002 *index_ptr
++ = '\0';
1004 header_name
= real_header_name
;
1007 if (index_ptr
|| (stack
& SWITCH_STACK_PUSH
) || (stack
& SWITCH_STACK_UNSHIFT
)) {
1009 if (!(header
= switch_event_get_header_ptr(event
, header_name
)) && index_ptr
) {
1011 header
= new_header(header_name
);
1013 if (switch_test_flag(event
, EF_UNIQ_HEADERS
)) {
1014 switch_event_del_header(event
, header_name
);
1020 if (header
|| (header
= switch_event_get_header_ptr(event
, header_name
))) {
1023 if (index
> -1 && index
<= 4000) {
1024 if (index
< header
->idx
) {
1025 FREE(header
->array
[index
]);
1026 header
->array
[index
] = DUP(data
);
1031 m
= realloc(header
->array
, sizeof(char *) * (index
+ 1));
1034 for (i
= header
->idx
; i
< index
; i
++) {
1037 m
[index
] = DUP(data
);
1038 header
->idx
= index
+ 1;
1048 if ((stack
& SWITCH_STACK_PUSH
) || (stack
& SWITCH_STACK_UNSHIFT
)) {
1050 stack
&= ~(SWITCH_STACK_TOP
| SWITCH_STACK_BOTTOM
);
1062 switch_event_del_header(event
, header_name
);
1067 if (switch_test_flag(event
, EF_UNIQ_HEADERS
)) {
1068 switch_event_del_header(event
, header_name
);
1071 if (!strncmp(data
, "ARRAY::", 7)) {
1072 switch_event_add_array(event
, header_name
, data
);
1078 header
= new_header(header_name
);
1081 if ((stack
& SWITCH_STACK_PUSH
) || (stack
& SWITCH_STACK_UNSHIFT
)) {
1083 switch_size_t len
= 0;
1087 if (header
->value
&& !header
->idx
) {
1088 m
= malloc(sizeof(char *));
1090 m
[0] = header
->value
;
1091 header
->value
= NULL
;
1097 i
= header
->idx
+ 1;
1098 m
= realloc(header
->array
, sizeof(char *) * i
);
1101 if ((stack
& SWITCH_STACK_PUSH
)) {
1102 m
[header
->idx
] = data
;
1103 } else if ((stack
& SWITCH_STACK_UNSHIFT
)) {
1104 for (j
= header
->idx
; j
> 0; j
--) {
1115 for(j
= 0; j
< header
->idx
; j
++) {
1116 len
+= strlen(header
->array
[j
]) + 2;
1121 hv
= realloc(header
->value
, len
);
1125 if (header
->idx
> 1) {
1126 switch_snprintf(header
->value
, len
, "ARRAY::");
1128 *header
->value
= '\0';
1131 hv
+= strlen(header
->value
);
1132 for(j
= 0; j
< header
->idx
; j
++) {
1134 memcpy(hv
, "|:", 2);
1137 memcpy(hv
, header
->array
[j
], strlen(header
->array
[j
]));
1138 hv
+= strlen(header
->array
[j
]);
1144 switch_safe_free(header
->value
);
1145 header
->value
= data
;
1149 header
->hash
= switch_ci_hashfunc_default(header
->name
, &hlen
);
1151 if ((stack
& SWITCH_STACK_TOP
)) {
1152 header
->next
= event
->headers
;
1153 event
->headers
= header
;
1154 if (!event
->last_header
) {
1155 event
->last_header
= header
;
1158 if (event
->last_header
) {
1159 event
->last_header
->next
= header
;
1161 event
->headers
= header
;
1162 header
->next
= NULL
;
1164 event
->last_header
= header
;
1170 switch_safe_free(real_header_name
);
1172 return SWITCH_STATUS_SUCCESS
;
1175 SWITCH_DECLARE(switch_status_t
) switch_event_add_header(switch_event_t
*event
, switch_stack_t stack
, const char *header_name
, const char *fmt
, ...)
1182 ret
= switch_vasprintf(&data
, fmt
, ap
);
1186 return SWITCH_STATUS_MEMERR
;
1189 return switch_event_base_add_header(event
, stack
, header_name
, data
);
1192 SWITCH_DECLARE(switch_status_t
) switch_event_set_subclass_name(switch_event_t
*event
, const char *subclass_name
)
1194 if (!event
|| !subclass_name
)
1195 return SWITCH_STATUS_GENERR
;
1197 switch_safe_free(event
->subclass_name
);
1198 event
->subclass_name
= DUP(subclass_name
);
1199 switch_event_del_header(event
, "Event-Subclass");
1200 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Subclass", event
->subclass_name
);
1201 return SWITCH_STATUS_SUCCESS
;
1204 SWITCH_DECLARE(switch_status_t
) switch_event_add_header_string(switch_event_t
*event
, switch_stack_t stack
, const char *header_name
, const char *data
)
1207 return switch_event_base_add_header(event
, stack
, header_name
, (stack
& SWITCH_STACK_NODUP
) ? (char *)data
: DUP(data
));
1209 return SWITCH_STATUS_GENERR
;
1212 SWITCH_DECLARE(switch_status_t
) switch_event_set_body(switch_event_t
*event
, const char *body
)
1214 switch_safe_free(event
->body
);
1217 event
->body
= DUP(body
);
1220 return SWITCH_STATUS_SUCCESS
;
1223 SWITCH_DECLARE(switch_status_t
) switch_event_add_body(switch_event_t
*event
, const char *fmt
, ...)
1231 ret
= switch_vasprintf(&data
, fmt
, ap
);
1235 return SWITCH_STATUS_GENERR
;
1237 switch_safe_free(event
->body
);
1239 return SWITCH_STATUS_SUCCESS
;
1242 return SWITCH_STATUS_GENERR
;
1246 SWITCH_DECLARE(void) switch_event_destroy(switch_event_t
**event
)
1248 switch_event_t
*ep
= *event
;
1249 switch_event_header_t
*hp
, *this;
1252 for (hp
= ep
->headers
; hp
;) {
1258 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "INDEX WITH NO ARRAY WTF?? [%s][%s]\n", this->name
, this->value
);
1262 for (i
= 0; i
< this->idx
; i
++) {
1263 FREE(this->array
[i
]);
1273 #ifdef SWITCH_EVENT_RECYCLE
1274 if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE
, this) != SWITCH_STATUS_SUCCESS
) {
1284 FREE(ep
->subclass_name
);
1285 #ifdef SWITCH_EVENT_RECYCLE
1286 if (switch_queue_trypush(EVENT_RECYCLE_QUEUE
, ep
) != SWITCH_STATUS_SUCCESS
) {
1298 SWITCH_DECLARE(void) switch_event_merge(switch_event_t
*event
, switch_event_t
*tomerge
)
1300 switch_event_header_t
*hp
;
1302 switch_assert(tomerge
&& event
);
1304 for (hp
= tomerge
->headers
; hp
; hp
= hp
->next
) {
1308 for(i
= 0; i
< hp
->idx
; i
++) {
1309 switch_event_add_header_string(event
, SWITCH_STACK_PUSH
, hp
->name
, hp
->array
[i
]);
1312 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, hp
->name
, hp
->value
);
1317 SWITCH_DECLARE(switch_status_t
) switch_event_dup(switch_event_t
**event
, switch_event_t
*todup
)
1319 switch_event_header_t
*hp
;
1321 if (switch_event_create_subclass(event
, SWITCH_EVENT_CLONE
, todup
->subclass_name
) != SWITCH_STATUS_SUCCESS
) {
1322 return SWITCH_STATUS_GENERR
;
1325 (*event
)->event_id
= todup
->event_id
;
1326 (*event
)->event_user_data
= todup
->event_user_data
;
1327 (*event
)->bind_user_data
= todup
->bind_user_data
;
1328 (*event
)->flags
= todup
->flags
;
1329 for (hp
= todup
->headers
; hp
; hp
= hp
->next
) {
1330 if (todup
->subclass_name
&& !strcmp(hp
->name
, "Event-Subclass")) {
1336 for (i
= 0; i
< hp
->idx
; i
++) {
1337 switch_event_add_header_string(*event
, SWITCH_STACK_PUSH
, hp
->name
, hp
->array
[i
]);
1340 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, hp
->name
, hp
->value
);
1345 (*event
)->body
= DUP(todup
->body
);
1348 (*event
)->key
= todup
->key
;
1350 return SWITCH_STATUS_SUCCESS
;
1354 SWITCH_DECLARE(switch_status_t
) switch_event_dup_reply(switch_event_t
**event
, switch_event_t
*todup
)
1356 switch_event_header_t
*hp
;
1357 char hname
[1024] = "";
1360 if (switch_event_create_subclass(event
, SWITCH_EVENT_CLONE
, todup
->subclass_name
) != SWITCH_STATUS_SUCCESS
) {
1361 return SWITCH_STATUS_GENERR
;
1364 (*event
)->event_id
= todup
->event_id
;
1365 (*event
)->event_user_data
= todup
->event_user_data
;
1366 (*event
)->bind_user_data
= todup
->bind_user_data
;
1367 (*event
)->flags
= todup
->flags
;
1369 for (hp
= todup
->headers
; hp
; hp
= hp
->next
) {
1370 char *name
= hp
->name
, *value
= hp
->value
;
1372 if (todup
->subclass_name
&& !strcmp(hp
->name
, "Event-Subclass")) {
1376 if (!strncasecmp(hp
->name
, "from_", 5)) {
1378 switch_snprintf(hname
, sizeof(hname
), "to_%s", p
);
1380 } else if (!strncasecmp(hp
->name
, "to_", 3)) {
1382 switch_snprintf(hname
, sizeof(hname
), "from_%s", p
);
1384 } else if (!strcasecmp(name
, "to")) {
1386 } else if (!strcasecmp(name
, "from")) {
1392 for (i
= 0; i
< hp
->idx
; i
++) {
1393 switch_event_add_header_string(*event
, SWITCH_STACK_PUSH
, name
, hp
->array
[i
]);
1396 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, name
, value
);
1400 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, "replying", "true");
1403 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, "orig_body", todup
->body
);
1406 (*event
)->key
= todup
->key
;
1408 return SWITCH_STATUS_SUCCESS
;
1411 #define SWITCH_SERIALIZED_EVENT_MAP "S(iiisss)A(S(ss))"
1413 SWITCH_DECLARE(switch_status_t
) switch_event_binary_deserialize(switch_event_t
**eventp
, void **data
, switch_size_t len
, switch_bool_t destroy
)
1416 switch_event_t
*event
;
1418 switch_serial_event_t e
;
1419 switch_serial_event_header_t sh
;
1422 switch_event_create(&event
, SWITCH_EVENT_CLONE
);
1423 switch_assert(event
);
1425 tn
= tpl_map(SWITCH_SERIALIZED_EVENT_MAP
, &e
, &sh
);
1428 how
|= TPL_EXCESS_OK
;
1431 tpl_load(tn
, how
, data
, len
);
1435 event
->event_id
= e
.event_id
;
1436 event
->priority
= e
.priority
;
1437 event
->flags
= e
.flags
;
1439 event
->owner
= e
.owner
;
1440 event
->subclass_name
= e
.subclass_name
;
1441 event
->body
= e
.body
;
1444 while (tpl_unpack(tn
, 1)) {
1445 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, sh
.name
, sh
.value
);
1458 return SWITCH_STATUS_SUCCESS
;
1460 return SWITCH_STATUS_FALSE
;
1465 SWITCH_DECLARE(switch_status_t
) switch_event_binary_serialize(switch_event_t
*event
, void **data
, switch_size_t
*len
)
1469 switch_serial_event_t e
;
1470 switch_serial_event_header_t sh
;
1471 switch_event_header_t
*eh
;
1474 e
.event_id
= event
->event_id
;
1475 e
.priority
= event
->priority
;
1476 e
.flags
= event
->flags
;
1478 e
.owner
= event
->owner
;
1479 e
.subclass_name
= event
->subclass_name
;
1480 e
.body
= event
->body
;
1482 tn
= tpl_map(SWITCH_SERIALIZED_EVENT_MAP
, &e
, &sh
);
1486 for (eh
= event
->headers
; eh
; eh
= eh
->next
) {
1487 if (eh
->idx
) continue; // no arrays yet
1490 sh
.value
= eh
->value
;
1496 how
|= TPL_PREALLOCD
;
1499 tpl_dump(tn
, how
, data
, len
);
1503 return SWITCH_STATUS_SUCCESS
;
1505 return SWITCH_STATUS_FALSE
;
1510 SWITCH_DECLARE(switch_status_t
) switch_event_serialize(switch_event_t
*event
, char **str
, switch_bool_t encode
)
1512 switch_size_t len
= 0;
1513 switch_event_header_t
*hp
;
1514 switch_size_t llen
= 0, dlen
= 0, blocksize
= 512, encode_len
= 1536, new_len
= 0;
1516 char *encode_buf
= NULL
; /* used for url encoding of variables to make sure unsafe things stay out of the serialized copy */
1520 dlen
= blocksize
* 2;
1522 if (!(buf
= malloc(dlen
))) {
1526 /* go ahead and give ourselves some space to work with, should save a few reallocs */
1527 if (!(encode_buf
= malloc(encode_len
))) {
1531 /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "hit serialized!.\n"); */
1532 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
1534 * grab enough memory to store 3x the string (url encode takes one char and turns it into %XX)
1535 * so we could end up with a string that is 3 times the originals length, unlikely but rather
1536 * be safe than destroy the string, also add one for the null. And try to be smart about using
1537 * the memory, allocate and only reallocate if we need more. This avoids an alloc, free CPU
1544 for(i
= 0; i
< hp
->idx
; i
++) {
1545 new_len
+= (strlen(hp
->array
[i
]) * 3) + 1;
1548 new_len
= (strlen(hp
->value
) * 3) + 1;
1551 if (encode_len
< new_len
) {
1554 /* keep track of the size of our allocation */
1555 encode_len
= new_len
;
1557 if (!(tmp
= realloc(encode_buf
, encode_len
))) {
1564 /* handle any bad things in the string like newlines : etc that screw up the serialized format */
1568 switch_url_encode(hp
->value
, encode_buf
, encode_len
);
1570 switch_snprintf(encode_buf
, encode_len
, "[%s]", hp
->value
);
1574 llen
= strlen(hp
->name
) + strlen(encode_buf
) + 8;
1576 if ((len
+ llen
) > dlen
) {
1578 dlen
+= (blocksize
+ (len
+ llen
));
1579 if (!(m
= realloc(buf
, dlen
))) {
1585 switch_snprintf(buf
+ len
, dlen
- len
, "%s: %s\n", hp
->name
, *encode_buf
== '\0' ? "_undef_" : encode_buf
);
1589 /* we are done with the memory we used for encoding, give it back */
1590 switch_safe_free(encode_buf
);
1593 int blen
= (int) strlen(event
->body
);
1602 if ((len
+ llen
) > dlen
) {
1604 dlen
+= (blocksize
+ (len
+ llen
));
1605 if (!(m
= realloc(buf
, dlen
))) {
1612 switch_snprintf(buf
+ len
, dlen
- len
, "Content-Length: %d\n\n%s", blen
, event
->body
);
1614 switch_snprintf(buf
+ len
, dlen
- len
, "\n");
1617 switch_snprintf(buf
+ len
, dlen
- len
, "\n");
1622 return SWITCH_STATUS_SUCCESS
;
1625 SWITCH_DECLARE(switch_status_t
) switch_event_create_array_pair(switch_event_t
**event
, char **names
, char **vals
, int len
)
1630 switch_event_create(event
, SWITCH_EVENT_CLONE
);
1632 for (r
= 0; r
< len
; r
++) {
1633 val
= switch_str_nil(vals
[r
]);
1640 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, name
, val
);
1643 return SWITCH_STATUS_SUCCESS
;
1647 SWITCH_DECLARE(switch_status_t
) switch_event_create_brackets(char *data
, char a
, char b
, char c
, switch_event_t
**event
, char **new_data
, switch_bool_t dup
)
1649 char *vdata
, *vdatap
= NULL
;
1650 char *end
, *check_a
, *check_b
;
1651 switch_event_t
*e
= *event
;
1652 char *var_array
[1024] = { 0 };
1654 char *next
= NULL
, *vnext
= NULL
;
1657 vdatap
= strdup(data
);
1663 end
= switch_find_end_paren(vdata
, a
, b
);
1667 while (check_a
&& (check_b
= switch_strchr_strict(check_a
, a
, " "))) {
1668 if ((check_b
= switch_find_end_paren(check_b
, a
, b
))) {
1673 if (check_a
) end
= check_a
;
1683 return SWITCH_STATUS_FALSE
;
1687 switch_event_create_plain(&e
, SWITCH_EVENT_CHANNEL_DATA
);
1688 e
->flags
|= EF_UNIQ_HEADERS
;
1698 if ((pnext
= switch_strchr_strict(next
, a
, " "))) {
1702 vnext
= switch_find_end_paren(next
, a
, b
);
1708 if (*vdata
== '^' && *(vdata
+ 1) == '^') {
1714 if ((var_count
= switch_separate_string(vdata
, c
, var_array
, (sizeof(var_array
) / sizeof(var_array
[0]))))) {
1716 for (x
= 0; x
< var_count
; x
++) {
1717 char *inner_var_array
[2] = { 0 };
1718 int inner_var_count
;
1720 if ((inner_var_count
= switch_separate_string(var_array
[x
], '=',
1721 inner_var_array
, (sizeof(inner_var_array
) / sizeof(inner_var_array
[0])))) == 2) {
1722 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG1
, "Parsing variable [%s]=[%s]\n", inner_var_array
[0], inner_var_array
[1]);
1723 switch_event_add_header_string(e
, SWITCH_STACK_BOTTOM
, inner_var_array
[0], inner_var_array
[1]);
1740 *new_data
= strdup(end
);
1746 return SWITCH_STATUS_SUCCESS
;
1752 SWITCH_DECLARE(switch_status_t
) switch_event_create_json(switch_event_t
**event
, const char *json
)
1754 switch_event_t
*new_event
;
1758 if (!(cj
= cJSON_Parse(json
))) {
1759 return SWITCH_STATUS_FALSE
;
1762 if (switch_event_create(&new_event
, SWITCH_EVENT_CLONE
) != SWITCH_STATUS_SUCCESS
) {
1764 return SWITCH_STATUS_FALSE
;
1767 for (cjp
= cj
->child
; cjp
; cjp
= cjp
->next
) {
1768 char *name
= cjp
->string
;
1769 char *value
= cjp
->valuestring
;
1771 if (name
&& value
) {
1772 if (!strcasecmp(name
, "_body")) {
1773 switch_event_add_body(new_event
, value
, SWITCH_VA_NONE
);
1775 if (!strcasecmp(name
, "event-name")) {
1776 switch_event_del_header(new_event
, "event-name");
1777 switch_name_event(value
, &new_event
->event_id
);
1780 switch_event_add_header_string(new_event
, SWITCH_STACK_BOTTOM
, name
, value
);
1784 if (cjp
->type
== cJSON_Array
) {
1785 int i
, x
= cJSON_GetArraySize(cjp
);
1787 for (i
= 0; i
< x
; i
++) {
1788 cJSON
*item
= cJSON_GetArrayItem(cjp
, i
);
1790 if (item
&& item
->type
== cJSON_String
&& item
->valuestring
) {
1791 switch_event_add_header_string(new_event
, SWITCH_STACK_PUSH
, name
, item
->valuestring
);
1800 return SWITCH_STATUS_SUCCESS
;
1803 SWITCH_DECLARE(switch_status_t
) switch_event_serialize_json_obj(switch_event_t
*event
, cJSON
**json
)
1805 switch_event_header_t
*hp
;
1808 cj
= cJSON_CreateObject();
1810 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
1812 cJSON
*a
= cJSON_CreateArray();
1815 for(i
= 0; i
< hp
->idx
; i
++) {
1816 cJSON_AddItemToArray(a
, cJSON_CreateString(hp
->array
[i
]));
1819 cJSON_AddItemToObject(cj
, hp
->name
, a
);
1822 cJSON_AddItemToObject(cj
, hp
->name
, cJSON_CreateString(hp
->value
));
1827 int blen
= (int) strlen(event
->body
);
1830 switch_snprintf(tmp
, sizeof(tmp
), "%d", blen
);
1832 cJSON_AddItemToObject(cj
, "Content-Length", cJSON_CreateString(tmp
));
1833 cJSON_AddItemToObject(cj
, "_body", cJSON_CreateString(event
->body
));
1838 return SWITCH_STATUS_SUCCESS
;
1841 SWITCH_DECLARE(switch_status_t
) switch_event_serialize_json(switch_event_t
*event
, char **str
)
1847 if (switch_event_serialize_json_obj(event
, &cj
) == SWITCH_STATUS_SUCCESS
) {
1848 *str
= cJSON_PrintUnformatted(cj
);
1851 return SWITCH_STATUS_SUCCESS
;
1854 return SWITCH_STATUS_FALSE
;
1857 static switch_xml_t
add_xml_header(switch_xml_t xml
, char *name
, char *value
, int offset
)
1859 switch_xml_t header
= switch_xml_add_child_d(xml
, name
, offset
);
1862 switch_size_t encode_len
= (strlen(value
) * 3) + 1;
1863 char *encode_buf
= malloc(encode_len
);
1865 switch_assert(encode_buf
);
1867 memset(encode_buf
, 0, encode_len
);
1868 switch_url_encode((char *) value
, encode_buf
, encode_len
);
1869 switch_xml_set_txt_d(header
, encode_buf
);
1876 SWITCH_DECLARE(switch_xml_t
) switch_event_xmlize(switch_event_t
*event
, const char *fmt
,...)
1878 switch_event_header_t
*hp
;
1879 char *data
= NULL
, *body
= NULL
;
1881 switch_xml_t xml
= NULL
;
1884 switch_xml_t xheaders
= NULL
;
1886 if (!(xml
= switch_xml_new("event"))) {
1892 #ifdef HAVE_VASPRINTF
1893 ret
= vasprintf(&data
, fmt
, ap
);
1895 data
= (char *) malloc(2048);
1900 ret
= vsnprintf(data
, 2048, fmt
, ap
);
1904 #ifndef HAVE_VASPRINTF
1911 if ((xheaders
= switch_xml_add_child_d(xml
, "headers", off
++))) {
1913 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
1917 for (i
= 0; i
< hp
->idx
; i
++) {
1918 add_xml_header(xheaders
, hp
->name
, hp
->array
[i
], hoff
++);
1921 add_xml_header(xheaders
, hp
->name
, hp
->value
, hoff
++);
1928 } else if (event
->body
) {
1933 int blen
= (int) strlen(body
);
1935 switch_snprintf(blena
, sizeof(blena
), "%d", blen
);
1937 switch_xml_t xbody
= NULL
;
1939 add_xml_header(xml
, "Content-Length", blena
, off
++);
1940 if ((xbody
= switch_xml_add_child_d(xml
, "body", off
++))) {
1941 switch_xml_set_txt_d(xbody
, body
);
1953 SWITCH_DECLARE(void) switch_event_prep_for_delivery_detailed(const char *file
, const char *func
, int line
, switch_event_t
*event
)
1955 switch_time_exp_t tm
;
1957 switch_size_t retsize
;
1958 switch_time_t ts
= switch_micro_time_now();
1961 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
1962 seq
= ++EVENT_SEQUENCE_NR
;
1963 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
1966 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Name", switch_event_name(event
->event_id
));
1967 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Core-UUID", switch_core_get_uuid());
1968 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-Hostname", switch_core_get_hostname());
1969 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-Switchname", switch_core_get_switchname());
1970 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-IPv4", guess_ip_v4
);
1971 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-IPv6", guess_ip_v6
);
1973 switch_time_exp_lt(&tm
, ts
);
1974 switch_strftime_nocheck(date
, &retsize
, sizeof(date
), "%Y-%m-%d %T", &tm
);
1975 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Date-Local", date
);
1976 switch_rfc822_date(date
, ts
);
1977 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Date-GMT", date
);
1978 switch_event_add_header(event
, SWITCH_STACK_BOTTOM
, "Event-Date-Timestamp", "%" SWITCH_UINT64_T_FMT
, (uint64_t) ts
);
1979 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Calling-File", switch_cut_path(file
));
1980 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Calling-Function", func
);
1981 switch_event_add_header(event
, SWITCH_STACK_BOTTOM
, "Event-Calling-Line-Number", "%d", line
);
1982 switch_event_add_header(event
, SWITCH_STACK_BOTTOM
, "Event-Sequence", "%" SWITCH_UINT64_T_FMT
, seq
);
1987 SWITCH_DECLARE(switch_status_t
) switch_event_fire_detailed(const char *file
, const char *func
, int line
, switch_event_t
**event
, void *user_data
)
1990 switch_assert(BLOCK
!= NULL
);
1991 switch_assert(RUNTIME_POOL
!= NULL
);
1992 switch_assert(EVENT_QUEUE_MUTEX
!= NULL
);
1993 switch_assert(RUNTIME_POOL
!= NULL
);
1995 if (SYSTEM_RUNNING
<= 0) {
1996 /* sorry we're closed */
1997 switch_event_destroy(event
);
1998 return SWITCH_STATUS_SUCCESS
;
2002 (*event
)->event_user_data
= user_data
;
2007 if (runtime
.events_use_dispatch
) {
2010 if (switch_event_queue_dispatch_event(event
) != SWITCH_STATUS_SUCCESS
) {
2011 switch_event_destroy(event
);
2012 return SWITCH_STATUS_FALSE
;
2015 switch_event_deliver_thread_pool(event
);
2018 return SWITCH_STATUS_SUCCESS
;
2021 SWITCH_DECLARE(switch_status_t
) switch_event_get_custom_events(switch_console_callback_match_t
**matches
)
2023 switch_hash_index_t
*hi
= NULL
;
2028 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
2030 for (hi
= switch_core_hash_first(CUSTOM_HASH
); hi
; hi
= switch_core_hash_next(&hi
)) {
2031 switch_core_hash_this(hi
, &var
, NULL
, &val
);
2032 switch_console_push_match(matches
, (const char *) var
);
2036 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
2038 return x
? SWITCH_STATUS_SUCCESS
: SWITCH_STATUS_FALSE
;
2041 SWITCH_DECLARE(switch_status_t
) switch_event_bind_removable(const char *id
, switch_event_types_t event
, const char *subclass_name
,
2042 switch_event_callback_t callback
, void *user_data
, switch_event_node_t
**node
)
2044 switch_event_node_t
*event_node
;
2045 switch_event_subclass_t
*subclass
= NULL
;
2047 switch_assert(BLOCK
!= NULL
);
2048 switch_assert(RUNTIME_POOL
!= NULL
);
2054 if (subclass_name
) {
2055 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
2057 if (!(subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
))) {
2058 switch_event_reserve_subclass_detailed(id
, subclass_name
);
2059 subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
);
2063 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
2066 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Could not reserve subclass. '%s'\n", subclass_name
);
2067 return SWITCH_STATUS_FALSE
;
2071 if (event
<= SWITCH_EVENT_ALL
) {
2072 switch_zmalloc(event_node
, sizeof(*event_node
));
2073 switch_thread_rwlock_wrlock(RWLOCK
);
2074 switch_mutex_lock(BLOCK
);
2075 /* <LOCKED> ----------------------------------------------- */
2076 event_node
->id
= DUP(id
);
2077 event_node
->event_id
= event
;
2078 if (subclass_name
) {
2079 event_node
->subclass_name
= DUP(subclass_name
);
2081 event_node
->callback
= callback
;
2082 event_node
->user_data
= user_data
;
2084 if (EVENT_NODES
[event
]) {
2085 event_node
->next
= EVENT_NODES
[event
];
2088 EVENT_NODES
[event
] = event_node
;
2089 switch_mutex_unlock(BLOCK
);
2090 switch_thread_rwlock_unlock(RWLOCK
);
2091 /* </LOCKED> ----------------------------------------------- */
2097 return SWITCH_STATUS_SUCCESS
;
2100 return SWITCH_STATUS_MEMERR
;
2104 SWITCH_DECLARE(switch_status_t
) switch_event_bind(const char *id
, switch_event_types_t event
, const char *subclass_name
,
2105 switch_event_callback_t callback
, void *user_data
)
2107 return switch_event_bind_removable(id
, event
, subclass_name
, callback
, user_data
, NULL
);
2111 SWITCH_DECLARE(switch_status_t
) switch_event_unbind_callback(switch_event_callback_t callback
)
2113 switch_event_node_t
*n
, *np
, *lnp
= NULL
;
2114 switch_status_t status
= SWITCH_STATUS_FALSE
;
2117 switch_thread_rwlock_wrlock(RWLOCK
);
2118 switch_mutex_lock(BLOCK
);
2119 /* <LOCKED> ----------------------------------------------- */
2120 for (id
= 0; id
<= SWITCH_EVENT_ALL
; id
++) {
2123 for (np
= EVENT_NODES
[id
]; np
;) {
2126 if (n
->callback
== callback
) {
2128 lnp
->next
= n
->next
;
2130 EVENT_NODES
[n
->event_id
] = n
->next
;
2133 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Event Binding deleted for %s:%s\n", n
->id
, switch_event_name(n
->event_id
));
2134 FREE(n
->subclass_name
);
2137 status
= SWITCH_STATUS_SUCCESS
;
2143 switch_mutex_unlock(BLOCK
);
2144 switch_thread_rwlock_unlock(RWLOCK
);
2145 /* </LOCKED> ----------------------------------------------- */
2152 SWITCH_DECLARE(switch_status_t
) switch_event_unbind(switch_event_node_t
**node
)
2154 switch_event_node_t
*n
, *np
, *lnp
= NULL
;
2155 switch_status_t status
= SWITCH_STATUS_FALSE
;
2163 switch_thread_rwlock_wrlock(RWLOCK
);
2164 switch_mutex_lock(BLOCK
);
2165 /* <LOCKED> ----------------------------------------------- */
2166 for (np
= EVENT_NODES
[n
->event_id
]; np
; np
= np
->next
) {
2169 lnp
->next
= n
->next
;
2171 EVENT_NODES
[n
->event_id
] = n
->next
;
2173 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Event Binding deleted for %s:%s\n", n
->id
, switch_event_name(n
->event_id
));
2174 FREE(n
->subclass_name
);
2178 status
= SWITCH_STATUS_SUCCESS
;
2183 switch_mutex_unlock(BLOCK
);
2184 switch_thread_rwlock_unlock(RWLOCK
);
2185 /* </LOCKED> ----------------------------------------------- */
2190 SWITCH_DECLARE(switch_status_t
) switch_event_create_pres_in_detailed(char *file
, char *func
, int line
,
2191 const char *proto
, const char *login
,
2192 const char *from
, const char *from_domain
,
2193 const char *status
, const char *event_type
,
2194 const char *alt_event_type
, int event_count
,
2195 const char *unique_id
, const char *channel_state
,
2196 const char *answer_state
, const char *call_direction
)
2198 switch_event_t
*pres_event
;
2200 if (switch_event_create_subclass(&pres_event
, SWITCH_EVENT_PRESENCE_IN
, SWITCH_EVENT_SUBCLASS_ANY
) == SWITCH_STATUS_SUCCESS
) {
2201 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "proto", proto
);
2202 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "login", login
);
2203 switch_event_add_header(pres_event
, SWITCH_STACK_TOP
, "from", "%s@%s", from
, from_domain
);
2204 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "status", status
);
2205 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "event_type", event_type
);
2206 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "alt_event_type", alt_event_type
);
2207 switch_event_add_header(pres_event
, SWITCH_STACK_TOP
, "event_count", "%d", event_count
);
2208 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "unique-id", alt_event_type
);
2209 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "channel-state", channel_state
);
2210 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "answer-state", answer_state
);
2211 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "presence-call-direction", call_direction
);
2212 switch_event_fire_detailed(file
, func
, line
, &pres_event
, NULL
);
2213 return SWITCH_STATUS_SUCCESS
;
2215 return SWITCH_STATUS_MEMERR
;
2218 #define resize(l) {\
2220 olen += (len + l + block);\
2222 if ((dp = realloc(data, olen))) {\
2225 memset(c, 0, olen - cpos);\
2228 SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event, const char *in, switch_event_t *var_list, switch_event_t *api_list, uint32_t recur)
2231 char *data
, *indup
, *endof_indup
;
2232 size_t sp
= 0, len
= 0, olen
= 0, vtype
= 0, br
= 0, cpos
, block
= 128;
2233 const char *sub_val
= NULL
;
2234 char *cloned_sub_val
= NULL
, *expanded_sub_val
= NULL
;
2235 char *func_val
= NULL
;
2237 char *gvar
= NULL
, *sb
= NULL
;
2247 nv
= switch_string_var_check_const(in
) || switch_string_has_escaped_data(in
);
2254 olen
= strlen(in
) + 1;
2256 switch_assert(indup
);
2257 endof_indup
= end_of_p(indup
) + 1;
2259 if ((data
= malloc(olen
))) {
2260 memset(data
, 0, olen
);
2262 for (p
= indup
; p
&& p
< endof_indup
&& *p
; p
++) {
2267 if (*(p
+ 1) == '$') {
2270 if (*(p
+ 1) == '$') {
2273 } else if (*(p
+ 1) == '\'') {
2276 } else if (*(p
+ 1) == '\\') {
2277 if (len
+ 1 >= olen
) {
2287 if (*p
== '$' && !nv
) {
2288 if (*(p
+ 1) == '$') {
2294 if (*(p
+ 1) == '{') {
2295 vtype
= global
? 3 : 1;
2305 if (len
+ 1 >= olen
) {
2316 char *s
= p
, *e
, *vname
, *vval
= NULL
;
2321 if ((vtype
== 1 || vtype
== 3) && *s
== '{') {
2329 if (br
== 1 && *e
== '}') {
2336 if (e
!= s
&& *e
== '{') {
2338 } else if (br
> 1 && *e
== '}') {
2345 p
= e
> endof_indup
? endof_indup
: e
;
2348 for(sb
= vname
; sb
&& *sb
; sb
++) {
2352 } else if (*sb
== '(') {
2371 } else if (br
> 1 && *e
== ')') {
2373 } else if (br
== 1 && *e
== ')') {
2383 if (vtype
== 1 || vtype
== 3) {
2384 char *expanded
= NULL
;
2390 if ((expanded
= switch_event_expand_headers_check(event
, (char *) vname
, var_list
, api_list
, recur
+1)) == vname
) {
2395 if ((ptr
= strchr(vname
, ':'))) {
2398 if ((ptr
= strchr(ptr
, ':'))) {
2400 ooffset
= atoi(ptr
);
2404 if ((ptr
= strchr(vname
, '[')) && strchr(ptr
, ']')) {
2409 if (vtype
== 3 || !(sub_val
= switch_event_get_header_idx(event
, vname
, idx
))) {
2410 switch_safe_free(gvar
);
2411 if ((gvar
= switch_core_get_variable_dup(vname
))) {
2415 if (var_list
&& !switch_event_check_permission_list(var_list
, vname
)) {
2416 sub_val
= "<Variable Expansion Permission Denied>";
2420 if ((expanded_sub_val
= switch_event_expand_headers_check(event
, sub_val
, var_list
, api_list
, recur
+1)) == sub_val
) {
2421 expanded_sub_val
= NULL
;
2423 sub_val
= expanded_sub_val
;
2428 if (offset
|| ooffset
) {
2429 cloned_sub_val
= strdup(sub_val
);
2430 switch_assert(cloned_sub_val
);
2431 sub_val
= cloned_sub_val
;
2436 } else if ((size_t) abs(offset
) <= strlen(sub_val
)) {
2437 sub_val
= cloned_sub_val
+ (strlen(cloned_sub_val
) + offset
);
2440 if (ooffset
> 0 && (size_t) ooffset
< strlen(sub_val
)) {
2441 if ((ptr
= (char *) sub_val
+ ooffset
)) {
2447 switch_safe_free(expanded
);
2449 switch_stream_handle_t stream
= { 0 };
2450 char *expanded
= NULL
;
2451 char *expanded_vname
= NULL
;
2453 SWITCH_STANDARD_STREAM(stream
);
2455 if ((expanded_vname
= switch_event_expand_headers_check(event
, (char *) vname
, var_list
, api_list
, recur
+1)) == vname
) {
2456 expanded_vname
= NULL
;
2458 vname
= expanded_vname
;
2461 if ((expanded
= switch_event_expand_headers_check(event
, vval
, var_list
, api_list
, recur
+1)) == vval
) {
2467 if (!switch_core_test_flag(SCF_API_EXPANSION
) || (api_list
&& !switch_event_check_permission_list(api_list
, vname
))) {
2469 sub_val
= "<API execute Permission Denied>";
2471 if (switch_api_execute(vname
, vval
, NULL
, &stream
) == SWITCH_STATUS_SUCCESS
) {
2472 func_val
= stream
.data
;
2479 switch_safe_free(expanded
);
2480 switch_safe_free(expanded_vname
);
2482 if ((nlen
= sub_val
? strlen(sub_val
) : 0)) {
2483 if (len
+ nlen
>= olen
) {
2492 switch_safe_free(func_val
);
2493 switch_safe_free(cloned_sub_val
);
2494 switch_safe_free(expanded_sub_val
);
2502 if (len
+ 1 >= olen
) {
2514 if (len
+ 1 >= olen
) {
2524 switch_safe_free(gvar
);
2529 SWITCH_DECLARE(char *) switch_event_build_param_string(switch_event_t
*event
, const char *prefix
, switch_hash_t
*vars_map
)
2531 switch_stream_handle_t stream
= { 0 };
2532 switch_size_t encode_len
= 1024, new_len
= 0;
2533 char *encode_buf
= NULL
;
2534 const char *prof
[12] = { 0 }, *prof_names
[12] = {
2537 switch_event_header_t
*hi
;
2541 SWITCH_STANDARD_STREAM(stream
);
2544 stream
.write_function(&stream
, "%s&", prefix
);
2547 encode_buf
= malloc(encode_len
);
2548 switch_assert(encode_buf
);
2552 for (x
= 0; prof
[x
]; x
++) {
2553 if (zstr(prof
[x
])) {
2556 new_len
= (strlen(prof
[x
]) * 3) + 1;
2557 if (encode_len
< new_len
) {
2560 encode_len
= new_len
;
2562 if (!(tmp
= realloc(encode_buf
, encode_len
))) {
2568 switch_url_encode(prof
[x
], encode_buf
, encode_len
);
2569 stream
.write_function(&stream
, "%s=%s&", prof_names
[x
], encode_buf
);
2573 if ((hi
= event
->headers
)) {
2575 for (; hi
; hi
= hi
->next
) {
2576 char *var
= hi
->name
;
2577 char *val
= hi
->value
;
2579 if (vars_map
!= NULL
) {
2580 if ((data
= switch_core_hash_find(vars_map
, var
)) == NULL
|| strcasecmp(((char *) data
), "enabled"))
2585 new_len
= (strlen((char *) val
) * 3) + 1;
2586 if (encode_len
< new_len
) {
2589 encode_len
= new_len
;
2591 tmp
= realloc(encode_buf
, encode_len
);
2596 switch_url_encode((char *) val
, encode_buf
, encode_len
);
2597 stream
.write_function(&stream
, "%s=%s&", (char *) var
, encode_buf
);
2603 e
= (char *) stream
.data
+ (strlen((char *) stream
.data
) - 1);
2605 if (e
&& *e
== '&') {
2609 switch_safe_free(encode_buf
);
2614 SWITCH_DECLARE(int) switch_event_check_permission_list(switch_event_t
*list
, const char *name
)
2618 int default_allow
= 0;
2624 default_allow
= switch_test_flag(list
, EF_DEFAULT_ALLOW
);
2626 if (!list
->headers
) {
2627 return default_allow
;
2630 if ((v
= switch_event_get_header(list
, name
))) {
2643 SWITCH_DECLARE(void) switch_json_add_presence_data_cols(switch_event_t
*event
, cJSON
*json
, const char *prefix
)
2647 if (!prefix
) prefix
= "";
2649 if ((data
= switch_event_get_header(event
, "presence_data_cols"))) {
2650 char *cols
[128] = { 0 };
2651 char header_name
[128] = "";
2652 int col_count
= 0, i
= 0;
2653 char *data_copy
= NULL
;
2655 data_copy
= strdup(data
);
2657 col_count
= switch_split(data_copy
, ':', cols
);
2659 for (i
= 0; i
< col_count
; i
++) {
2660 const char *val
= NULL
;
2661 switch_snprintf(header_name
, sizeof(header_name
), "%s%s", prefix
, cols
[i
]);
2663 val
= switch_event_get_header(event
, cols
[i
]);
2664 json_add_child_string(json
, header_name
, val
);
2667 switch_safe_free(data_copy
);
2673 SWITCH_DECLARE(void) switch_event_add_presence_data_cols(switch_channel_t
*channel
, switch_event_t
*event
, const char *prefix
)
2677 if (!prefix
) prefix
= "";
2679 if ((data
= switch_channel_get_variable(channel
, "presence_data_cols"))) {
2680 char *cols
[128] = { 0 };
2681 char header_name
[128] = "";
2682 int col_count
= 0, i
= 0;
2683 char *data_copy
= NULL
;
2685 data_copy
= strdup(data
);
2687 col_count
= switch_split(data_copy
, ':', cols
);
2689 for (i
= 0; i
< col_count
; i
++) {
2690 const char *val
= NULL
;
2691 switch_snprintf(header_name
, sizeof(header_name
), "%s%s", prefix
, cols
[i
]);
2693 val
= switch_channel_get_variable(channel
, cols
[i
]);
2694 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, header_name
, val
);
2697 switch_safe_free(data_copy
);
2702 struct switch_event_channel_sub_node_head_s
;
2703 typedef struct switch_event_channel_sub_node_s
{
2704 switch_event_channel_func_t func
;
2706 switch_event_channel_id_t id
;
2707 struct switch_event_channel_sub_node_head_s
*head
;
2708 struct switch_event_channel_sub_node_s
*next
;
2709 } switch_event_channel_sub_node_t
;
2711 typedef struct switch_event_channel_sub_node_head_s
{
2712 switch_event_channel_sub_node_t
*node
;
2713 switch_event_channel_sub_node_t
*tail
;
2714 char *event_channel
;
2715 } switch_event_channel_sub_node_head_t
;
2717 static uint32_t switch_event_channel_unsub_head(switch_event_channel_func_t func
, switch_event_channel_sub_node_head_t
*head
, void *user_data
)
2721 switch_event_channel_sub_node_t
*thisnp
= NULL
, *np
, *last
= NULL
;
2723 np
= head
->tail
= head
->node
;
2730 if (!(func
) || (thisnp
->func
== func
&& (thisnp
->user_data
== user_data
|| user_data
== NULL
))) {
2740 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG1
, "UNSUBBING %p [%s]\n", (void *)(intptr_t)thisnp
->func
, thisnp
->head
->event_channel
);
2743 thisnp
->func
= NULL
;
2754 static void unsub_all_switch_event_channel(void)
2756 switch_hash_index_t
*hi
= NULL
;
2759 switch_event_channel_sub_node_head_t
*head
;
2761 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
2763 while ((hi
= switch_core_hash_first_iter( event_channel_manager
.perm_hash
, hi
))) {
2764 switch_event_t
*vals
= NULL
;
2765 switch_core_hash_this(hi
, &var
, NULL
, &val
);
2766 vals
= (switch_event_t
*) val
;
2767 switch_core_hash_delete(event_channel_manager
.perm_hash
, var
);
2768 switch_event_destroy(&vals
);
2771 while ((hi
= switch_core_hash_first_iter( event_channel_manager
.hash
, hi
))) {
2772 switch_core_hash_this(hi
, NULL
, NULL
, &val
);
2773 head
= (switch_event_channel_sub_node_head_t
*) val
;
2774 switch_event_channel_unsub_head(NULL
, head
, NULL
);
2775 switch_core_hash_delete(event_channel_manager
.hash
, head
->event_channel
);
2776 free(head
->event_channel
);
2780 switch_safe_free(hi
);
2781 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2784 static uint32_t switch_event_channel_unsub_channel(switch_event_channel_func_t func
, const char *event_channel
, void *user_data
)
2786 switch_event_channel_sub_node_head_t
*head
;
2789 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
2791 if (!event_channel
) {
2792 switch_hash_index_t
*hi
;
2795 for (hi
= switch_core_hash_first(event_channel_manager
.hash
); hi
; hi
= switch_core_hash_next(&hi
)) {
2796 switch_core_hash_this(hi
, NULL
, NULL
, &val
);
2799 head
= (switch_event_channel_sub_node_head_t
*) val
;
2800 x
+= switch_event_channel_unsub_head(func
, head
, user_data
);
2805 if ((head
= switch_core_hash_find(event_channel_manager
.hash
, event_channel
))) {
2806 x
+= switch_event_channel_unsub_head(func
, head
, user_data
);
2810 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2815 static switch_status_t
switch_event_channel_sub_channel(const char *event_channel
, switch_event_channel_func_t func
, switch_event_channel_id_t id
, void *user_data
)
2818 switch_event_channel_sub_node_t
*node
, *np
;
2819 switch_event_channel_sub_node_head_t
*head
;
2820 switch_status_t status
= SWITCH_STATUS_FALSE
;
2822 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
2824 if (!(head
= switch_core_hash_find(event_channel_manager
.hash
, event_channel
))) {
2825 switch_zmalloc(head
, sizeof(*head
));
2826 head
->event_channel
= strdup(event_channel
);
2827 switch_core_hash_insert(event_channel_manager
.hash
, event_channel
, head
);
2829 switch_zmalloc(node
, sizeof(*node
));
2831 node
->user_data
= user_data
;
2837 status
= SWITCH_STATUS_SUCCESS
;
2841 for (np
= head
->node
; np
; np
= np
->next
) {
2842 if (np
->func
== func
&& np
->user_data
== user_data
) {
2849 switch_zmalloc(node
, sizeof(*node
));
2852 node
->user_data
= user_data
;
2861 head
->tail
->next
= node
;
2862 head
->tail
= head
->tail
->next
;
2864 status
= SWITCH_STATUS_SUCCESS
;
2868 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2874 char *event_channel
;
2877 switch_event_channel_id_t id
;
2878 } event_channel_data_t
;
2882 static uint32_t _switch_event_channel_broadcast(const char *event_channel
, const char *broadcast_channel
,
2883 cJSON
*json
, const char *key
, switch_event_channel_id_t id
)
2885 switch_event_channel_sub_node_t
*np
;
2886 switch_event_channel_sub_node_head_t
*head
;
2889 switch_thread_rwlock_rdlock(event_channel_manager
.rwlock
);
2890 if ((head
= switch_core_hash_find(event_channel_manager
.hash
, event_channel
))) {
2891 for (np
= head
->node
; np
; np
= np
->next
) {
2896 np
->func(broadcast_channel
, json
, key
, id
, np
->user_data
);
2900 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2905 static void destroy_ecd(event_channel_data_t
**ecdP
)
2907 event_channel_data_t
*ecd
= *ecdP
;
2910 switch_safe_free(ecd
->event_channel
);
2911 switch_safe_free(ecd
->key
);
2913 cJSON_Delete(ecd
->json
);
2920 #ifndef SWITCH_CHANNEL_DISPATCH_MAX_KEY_PARTS
2921 #define SWITCH_CHANNEL_DISPATCH_MAX_KEY_PARTS 10
2924 static void ecd_deliver(event_channel_data_t
**ecdP
)
2926 event_channel_data_t
*ecd
= *ecdP
;
2932 t
= _switch_event_channel_broadcast(ecd
->event_channel
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2934 key
= strdup(ecd
->event_channel
);
2935 if (switch_core_test_flag(SCF_EVENT_CHANNEL_ENABLE_HIERARCHY_DELIVERY
)) {
2936 const char *sep
= switch_core_get_event_channel_key_separator();
2937 char *x_argv
[SWITCH_CHANNEL_DISPATCH_MAX_KEY_PARTS
] = { 0 };
2938 int x_argc
= switch_separate_string_string(key
, (char*) sep
, x_argv
, SWITCH_CHANNEL_DISPATCH_MAX_KEY_PARTS
);
2941 for(i
=x_argc
- 1; i
> 0; i
--) {
2943 memset(buf
, 0, 1024);
2944 sprintf(buf
, "%s", x_argv
[0]);
2945 for(z
=1; z
< i
; z
++) {
2947 strcat(buf
, x_argv
[z
]);
2949 r
= _switch_event_channel_broadcast(buf
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2951 if (r
&& switch_core_test_flag(SCF_EVENT_CHANNEL_HIERARCHY_DELIVERY_ONCE
)) {
2957 if ((p
= strchr(key
, '.'))) {
2959 t
+= _switch_event_channel_broadcast(key
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2962 switch_safe_free(key
);
2964 t
+= _switch_event_channel_broadcast(SWITCH_EVENT_CHANNEL_GLOBAL
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2967 if (switch_core_test_flag(SCF_EVENT_CHANNEL_LOG_UNDELIVERABLE_JSON
)) {
2968 char *json
= cJSON_Print(ecd
->json
);
2969 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "no subscribers for %s , %s => %s\n", ecd
->event_channel
, ecd
->key
, json
);
2970 switch_safe_free(json
);
2972 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "no subscribers for %s , %s\n", ecd
->event_channel
, ecd
->key
);
2975 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG1
, "delivered to %u subscribers for %s\n", t
, ecd
->event_channel
);
2981 static void *SWITCH_THREAD_FUNC
switch_event_channel_deliver_thread(switch_thread_t
*thread
, void *obj
)
2983 switch_queue_t
*queue
= (switch_queue_t
*) obj
;
2985 event_channel_data_t
*ecd
= NULL
;
2987 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
2989 EVENT_CHANNEL_DISPATCH_THREAD_COUNT
++;
2990 EVENT_CHANNEL_DISPATCH_THREAD_STARTING
= 0;
2991 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
2993 while(SYSTEM_RUNNING
) {
2995 if (switch_queue_pop(queue
, &pop
) != SWITCH_STATUS_SUCCESS
) {
3003 ecd
= (event_channel_data_t
*) pop
;
3008 while (switch_queue_trypop(queue
, &pop
) == SWITCH_STATUS_SUCCESS
) {
3009 ecd
= (event_channel_data_t
*) pop
;
3013 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
3015 EVENT_CHANNEL_DISPATCH_THREAD_COUNT
--;
3016 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
3018 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Event Channel Dispatch Thread Ended.\n");
3022 SWITCH_DECLARE(switch_status_t
) switch_event_channel_broadcast(const char *event_channel
, cJSON
**json
, const char *key
, switch_event_channel_id_t id
)
3024 event_channel_data_t
*ecd
= NULL
;
3025 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
3028 if (!SYSTEM_RUNNING
) {
3029 cJSON_Delete(*json
);
3031 return SWITCH_STATUS_FALSE
;
3034 switch_zmalloc(ecd
, sizeof(*ecd
));
3036 ecd
->event_channel
= strdup(event_channel
);
3038 ecd
->key
= strdup(key
);
3043 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
3044 if (!EVENT_CHANNEL_DISPATCH_THREAD_COUNT
&& !EVENT_CHANNEL_DISPATCH_THREAD_STARTING
&& SYSTEM_RUNNING
) {
3045 EVENT_CHANNEL_DISPATCH_THREAD_STARTING
= 1;
3048 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
3051 switch_thread_data_t
*td
;
3053 if (!EVENT_CHANNEL_DISPATCH_QUEUE
) {
3054 switch_queue_create(&EVENT_CHANNEL_DISPATCH_QUEUE
, DISPATCH_QUEUE_LEN
* MAX_DISPATCH
, THRUNTIME_POOL
);
3057 td
= malloc(sizeof(*td
));
3061 td
->func
= switch_event_channel_deliver_thread
;
3062 td
->obj
= EVENT_CHANNEL_DISPATCH_QUEUE
;
3065 switch_thread_pool_launch_thread(&td
);
3068 if ((status
= switch_queue_trypush(EVENT_CHANNEL_DISPATCH_QUEUE
, ecd
)) != SWITCH_STATUS_SUCCESS
) {
3069 cJSON_Delete(ecd
->json
);
3072 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "Event Channel Queue failure for channel %s\n", event_channel
);
3080 SWITCH_DECLARE(switch_status_t
) switch_event_channel_deliver(const char *event_channel
, cJSON
**json
, const char *key
, switch_event_channel_id_t id
)
3082 event_channel_data_t
*ecd
= NULL
;
3083 switch_zmalloc(ecd
, sizeof(*ecd
));
3085 ecd
->event_channel
= strdup(event_channel
);
3087 ecd
->key
= strdup(key
);
3094 return SWITCH_STATUS_SUCCESS
;
3097 SWITCH_DECLARE(uint32_t) switch_event_channel_unbind(const char *event_channel
, switch_event_channel_func_t func
, void *user_data
)
3099 return switch_event_channel_unsub_channel(func
, event_channel
, user_data
);
3102 SWITCH_DECLARE(switch_status_t
) switch_event_channel_bind(const char *event_channel
, switch_event_channel_func_t func
, switch_event_channel_id_t
*id
, void *user_data
)
3104 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
3109 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
3110 *id
= event_channel_manager
.ID
++;
3111 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3114 status
= switch_event_channel_sub_channel(event_channel
, func
, *id
, user_data
);
3119 SWITCH_DECLARE(switch_bool_t
) switch_event_channel_permission_verify(const char *cookie
, const char *event_channel
)
3121 switch_event_t
*vals
;
3122 switch_bool_t r
= SWITCH_FALSE
;
3124 switch_thread_rwlock_rdlock(event_channel_manager
.rwlock
);
3125 if ((vals
= switch_core_hash_find(event_channel_manager
.perm_hash
, cookie
))) {
3126 r
= switch_true(switch_event_get_header(vals
, event_channel
));
3128 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3133 SWITCH_DECLARE(void) switch_event_channel_permission_modify(const char *cookie
, const char *event_channel
, switch_bool_t set
)
3135 switch_event_t
*vals
;
3137 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
3138 if (!(vals
= switch_core_hash_find(event_channel_manager
.perm_hash
, cookie
))) {
3141 switch_event_create_plain(&vals
, SWITCH_EVENT_CHANNEL_DATA
);
3142 switch_core_hash_insert(event_channel_manager
.perm_hash
, cookie
, vals
);
3146 switch_event_add_header_string(vals
, SWITCH_STACK_BOTTOM
, event_channel
, "true");
3148 switch_event_del_header(vals
, event_channel
);
3154 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3157 SWITCH_DECLARE(void) switch_event_channel_permission_clear(const char *cookie
)
3159 switch_event_t
*vals
;
3161 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
3162 if ((vals
= switch_core_hash_find(event_channel_manager
.perm_hash
, cookie
))) {
3163 switch_core_hash_delete(event_channel_manager
.perm_hash
, cookie
);
3164 switch_event_destroy(&vals
);
3166 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3170 typedef struct alias_node_s
{
3171 char *event_channel
;
3174 struct alias_node_s
*next
;
3177 typedef struct la_node_s
{
3180 struct la_node_s
*next
;
3184 struct switch_live_array_s
{
3185 char *event_channel
;
3190 switch_memory_pool_t
*pool
;
3191 switch_hash_t
*hash
;
3192 switch_mutex_t
*mutex
;
3195 switch_bool_t visible
;
3197 switch_event_channel_id_t channel_id
;
3198 switch_live_array_command_handler_t command_handler
;
3200 alias_node_t
*aliases
;
3204 static switch_status_t
la_broadcast(switch_live_array_t
*la
, cJSON
**json
)
3209 switch_mutex_lock(la
->mutex
);
3210 for (np
= la
->aliases
; np
; np
= np
->next
) {
3211 cJSON
*dup
= cJSON_Duplicate(*json
, 1);
3212 cJSON
*data
= cJSON_GetObjectItem(dup
, "data");
3214 cJSON_ReplaceItemInObject(dup
, "eventChannel", cJSON_CreateString(np
->event_channel
));
3215 cJSON_ReplaceItemInObject(data
, "name", cJSON_CreateString(np
->name
));
3217 switch_event_channel_broadcast(np
->event_channel
, &dup
, __FILE__
, la
->channel_id
);
3219 switch_mutex_unlock(la
->mutex
);
3222 return switch_event_channel_broadcast(la
->event_channel
, json
, __FILE__
, la
->channel_id
);
3227 SWITCH_DECLARE(switch_status_t
) switch_live_array_visible(switch_live_array_t
*la
, switch_bool_t visible
, switch_bool_t force
)
3229 switch_status_t status
= SWITCH_STATUS_FALSE
;
3231 switch_mutex_lock(la
->mutex
);
3232 if (la
->visible
!= visible
|| force
) {
3235 msg
= cJSON_CreateObject();
3236 data
= json_add_child_obj(msg
, "data", NULL
);
3238 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3239 cJSON_AddItemToObject(data
, "action", cJSON_CreateString(visible
? "hide" : "show"));
3240 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3242 la_broadcast(la
, &msg
);
3244 la
->visible
= visible
;
3246 switch_mutex_unlock(la
->mutex
);
3251 SWITCH_DECLARE(switch_status_t
) switch_live_array_clear(switch_live_array_t
*la
)
3253 la_node_t
*cur
, *np
;
3256 switch_mutex_lock(la
->mutex
);
3259 msg
= cJSON_CreateObject();
3260 data
= json_add_child_obj(msg
, "data", NULL
);
3262 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3263 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("clear"));
3264 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3265 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(-1));
3266 cJSON_AddItemToObject(data
, "data", cJSON_CreateObject());
3268 la_broadcast(la
, &msg
);
3273 cJSON_Delete(cur
->obj
);
3278 la
->head
= la
->tail
= NULL
;
3280 switch_mutex_unlock(la
->mutex
);
3282 return SWITCH_STATUS_SUCCESS
;
3285 SWITCH_DECLARE(switch_status_t
) switch_live_array_bootstrap(switch_live_array_t
*la
, const char *sessid
, switch_event_channel_id_t channel_id
)
3290 switch_mutex_lock(la
->mutex
);
3293 msg
= cJSON_CreateObject();
3294 data
= json_add_child_obj(msg
, "data", NULL
);
3296 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3297 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("clear"));
3298 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3299 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(-1));
3300 cJSON_AddItemToObject(data
, "data", cJSON_CreateObject());
3302 switch_event_channel_broadcast(la
->event_channel
, &msg
, __FILE__
, channel_id
);
3304 for (np
= la
->head
; np
; np
= np
->next
) {
3305 msg
= cJSON_CreateObject();
3306 data
= json_add_child_obj(msg
, "data", NULL
);
3308 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3309 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("add"));
3310 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3311 cJSON_AddItemToObject(data
, "hashKey", cJSON_CreateString(np
->name
));
3312 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3313 cJSON_AddItemToObject(data
, "data", cJSON_Duplicate(np
->obj
, 1));
3315 cJSON_AddItemToObject(msg
, "sessid", cJSON_CreateString(sessid
));
3317 switch_event_channel_broadcast(la
->event_channel
, &msg
, __FILE__
, channel_id
);
3322 msg
= cJSON_CreateObject();
3323 data
= json_add_child_obj(msg
, "data", NULL
);
3325 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3326 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("bootObj"));
3327 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3328 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(-1));
3331 cJSON_AddItemToObject(msg
, "sessid", cJSON_CreateString(sessid
));
3334 data
= json_add_child_array(data
, "data");
3336 for (np
= la
->head
; np
; np
= np
->next
) {
3337 cJSON
*row
= cJSON_CreateArray();
3338 cJSON_AddItemToArray(row
, cJSON_CreateString(np
->name
));
3339 cJSON_AddItemToArray(row
, cJSON_Duplicate(np
->obj
, 1));
3340 cJSON_AddItemToArray(data
, row
);
3343 switch_event_channel_broadcast(la
->event_channel
, &msg
, __FILE__
, channel_id
);
3349 switch_live_array_visible(la
, SWITCH_FALSE
, SWITCH_TRUE
);
3352 switch_mutex_unlock(la
->mutex
);
3354 return SWITCH_STATUS_SUCCESS
;
3357 SWITCH_DECLARE(switch_status_t
) switch_live_array_destroy(switch_live_array_t
**live_arrayP
)
3359 switch_live_array_t
*la
= *live_arrayP
;
3360 switch_memory_pool_t
*pool
;
3364 *live_arrayP
= NULL
;
3366 switch_mutex_lock(la
->mutex
);
3370 if (la
->refs
) done
= 1;
3371 switch_mutex_unlock(la
->mutex
);
3374 return SWITCH_STATUS_SUCCESS
;
3379 switch_live_array_clear(la
);
3381 switch_core_hash_destroy(&la
->hash
);
3383 switch_mutex_lock(event_channel_manager
.lamutex
);
3384 switch_core_hash_delete(event_channel_manager
.lahash
, la
->key
);
3385 for (np
= la
->aliases
; np
; np
= np
->next
) {
3386 switch_core_hash_delete(event_channel_manager
.lahash
, np
->key
);
3388 switch_mutex_unlock(event_channel_manager
.lamutex
);
3390 switch_core_destroy_memory_pool(&pool
);
3392 return SWITCH_STATUS_SUCCESS
;
3395 SWITCH_DECLARE(switch_bool_t
) switch_live_array_isnew(switch_live_array_t
*la
)
3400 SWITCH_DECLARE(switch_bool_t
) switch_live_array_clear_alias(switch_live_array_t
*la
, const char *event_channel
, const char *name
)
3402 alias_node_t
*np
, *last
= NULL
, *del
= NULL
;
3403 switch_bool_t r
= SWITCH_FALSE
;
3405 switch_mutex_lock(la
->mutex
);
3406 for (np
= la
->aliases
; np
; np
= np
->next
) {
3407 if (!strcmp(np
->event_channel
, event_channel
) && !strcmp(np
->name
, name
)) {
3412 last
->next
= np
->next
;
3414 la
->aliases
= np
->next
;
3420 switch_mutex_unlock(la
->mutex
);
3423 switch_mutex_lock(event_channel_manager
.lamutex
);
3424 switch_core_hash_delete(event_channel_manager
.lahash
, del
->key
);
3425 switch_mutex_unlock(event_channel_manager
.lamutex
);
3432 SWITCH_DECLARE(switch_bool_t
) switch_live_array_add_alias(switch_live_array_t
*la
, const char *event_channel
, const char *name
)
3434 alias_node_t
*node
= 0, *np
;
3435 switch_bool_t exist
= SWITCH_FALSE
;
3437 switch_mutex_lock(la
->mutex
);
3438 for (np
= la
->aliases
; np
&& np
->next
; np
= np
->next
) {
3439 if (!strcmp(np
->event_channel
, event_channel
) && !strcmp(np
->name
, name
)) {
3440 exist
= SWITCH_TRUE
;
3446 node
= switch_core_alloc(la
->pool
, sizeof(*node
));
3447 node
->event_channel
= switch_core_strdup(la
->pool
, event_channel
);
3448 node
->name
= switch_core_strdup(la
->pool
, name
);
3449 node
->key
= switch_core_sprintf(la
->pool
, "%s.%s", event_channel
, name
);
3458 switch_mutex_unlock(la
->mutex
);
3461 switch_mutex_lock(event_channel_manager
.lamutex
);
3462 switch_core_hash_insert(event_channel_manager
.lahash
, node
->key
, la
);
3463 switch_mutex_unlock(event_channel_manager
.lamutex
);
3470 SWITCH_DECLARE(switch_status_t
) switch_live_array_create(const char *event_channel
, const char *name
,
3471 switch_event_channel_id_t channel_id
, switch_live_array_t
**live_arrayP
)
3473 switch_live_array_t
*la
= NULL
;
3474 switch_memory_pool_t
*pool
;
3477 switch_core_new_memory_pool(&pool
);
3478 key
= switch_core_sprintf(pool
, "%s.%s", event_channel
, name
);
3480 switch_mutex_lock(event_channel_manager
.lamutex
);
3481 la
= switch_core_hash_find(event_channel_manager
.lahash
, key
);
3482 switch_mutex_unlock(event_channel_manager
.lamutex
);
3485 la
->new = SWITCH_FALSE
;
3487 la
= switch_core_alloc(pool
, sizeof(*la
));
3490 la
->visible
= SWITCH_TRUE
;
3491 la
->event_channel
= switch_core_strdup(la
->pool
, event_channel
);
3492 la
->name
= switch_core_strdup(la
->pool
, name
);
3494 la
->new = SWITCH_TRUE
;
3495 la
->channel_id
= channel_id
;
3496 switch_core_hash_init(&la
->hash
);
3497 switch_mutex_init(&la
->mutex
, SWITCH_MUTEX_NESTED
, la
->pool
);
3499 switch_mutex_lock(event_channel_manager
.lamutex
);
3500 switch_core_hash_insert(event_channel_manager
.lahash
, la
->key
, la
);
3501 switch_mutex_unlock(event_channel_manager
.lamutex
);
3504 switch_mutex_lock(la
->mutex
);
3506 switch_mutex_unlock(la
->mutex
);
3510 return SWITCH_STATUS_SUCCESS
;
3513 SWITCH_DECLARE(cJSON
*) switch_live_array_get(switch_live_array_t
*la
, const char *name
)
3518 switch_mutex_lock(la
->mutex
);
3519 if ((node
= switch_core_hash_find(la
->hash
, name
))) {
3520 dup
= cJSON_Duplicate(node
->obj
, 1);
3522 switch_mutex_unlock(la
->mutex
);
3527 SWITCH_DECLARE(cJSON
*) switch_live_array_get_idx(switch_live_array_t
*la
, int idx
)
3532 switch_mutex_lock(la
->mutex
);
3533 for (node
= la
->head
; node
; node
= node
->next
) {
3534 if (node
->pos
== idx
) {
3535 dup
= cJSON_Duplicate(node
->obj
, 1);
3539 switch_mutex_unlock(la
->mutex
);
3544 SWITCH_DECLARE(void) switch_live_array_lock(switch_live_array_t
*la
)
3546 switch_mutex_lock(la
->mutex
);
3549 SWITCH_DECLARE(void) switch_live_array_unlock(switch_live_array_t
*la
)
3551 switch_mutex_unlock(la
->mutex
);
3554 SWITCH_DECLARE(switch_status_t
) switch_live_array_del(switch_live_array_t
*la
, const char *name
)
3556 switch_status_t status
= SWITCH_STATUS_FALSE
;
3557 la_node_t
*node
, *cur
, *np
, *last
= NULL
;
3558 cJSON
*msg
, *data
= NULL
;
3560 switch_mutex_lock(la
->mutex
);
3561 if ((node
= switch_core_hash_find(la
->hash
, name
))) {
3570 last
->next
= cur
->next
;
3572 la
->head
= cur
->next
;
3574 switch_core_hash_delete(la
->hash
, name
);
3576 msg
= cJSON_CreateObject();
3577 data
= json_add_child_obj(msg
, "data", NULL
);
3579 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3580 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3581 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("del"));
3582 cJSON_AddItemToObject(data
, "hashKey", cJSON_CreateString(cur
->name
));
3583 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3584 cJSON_AddItemToObject(data
, "data", cur
->obj
);
3587 la_broadcast(la
, &msg
);
3591 cur
->pos
= la
->pos
++;
3597 switch_mutex_unlock(la
->mutex
);
3602 SWITCH_DECLARE(switch_status_t
) switch_live_array_add(switch_live_array_t
*la
, const char *name
, int index
, cJSON
**obj
, switch_bool_t duplicate
)
3605 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
3606 const char *action
= "add";
3607 cJSON
*msg
= NULL
, *data
= NULL
;
3609 switch_mutex_lock(la
->mutex
);
3611 if ((node
= switch_core_hash_find(la
->hash
, name
))) {
3617 cJSON_Delete(node
->obj
);
3622 switch_zmalloc(node
, sizeof(*node
));
3624 node
->name
= strdup(name
);
3625 switch_core_hash_insert(la
->hash
, name
, node
);
3627 if (index
> -1 && index
< la
->pos
&& la
->head
) {
3628 la_node_t
*np
, *last
= NULL
;
3631 for(np
= la
->head
; np
; np
= np
->next
) {
3635 node
->next
= last
->next
;
3639 node
->next
= la
->head
;
3654 node
->pos
= la
->pos
++;
3660 la
->tail
->next
= node
;
3668 node
->obj
= cJSON_Duplicate(*obj
, 1);
3673 msg
= cJSON_CreateObject();
3674 data
= json_add_child_obj(msg
, "data", NULL
);
3676 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3677 cJSON_AddItemToObject(data
, "action", cJSON_CreateString(action
));
3680 cJSON_AddItemToObject(data
, "arrIndex", cJSON_CreateNumber(index
));
3683 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3684 cJSON_AddItemToObject(data
, "hashKey", cJSON_CreateString(node
->name
));
3685 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3686 cJSON_AddItemToObject(data
, "data", cJSON_Duplicate(node
->obj
, 1));
3688 la_broadcast(la
, &msg
);
3690 switch_mutex_unlock(la
->mutex
);
3695 SWITCH_DECLARE(void) switch_live_array_set_user_data(switch_live_array_t
*la
, void *user_data
)
3698 la
->user_data
= user_data
;
3701 SWITCH_DECLARE(void) switch_live_array_set_command_handler(switch_live_array_t
*la
, switch_live_array_command_handler_t command_handler
)
3704 la
->command_handler
= command_handler
;
3708 SWITCH_DECLARE(void) switch_live_array_parse_json(cJSON
*json
, switch_event_channel_id_t channel_id
)
3710 const char *context
= NULL
, *name
= NULL
;
3711 switch_live_array_t
*la
= NULL
;
3714 if ((jla
= cJSON_GetObjectItem(json
, "data")) && (jla
= cJSON_GetObjectItem(jla
, "liveArray"))) {
3716 if ((context
= cJSON_GetObjectCstr(jla
, "context")) && (name
= cJSON_GetObjectCstr(jla
, "name"))) {
3717 const char *command
= cJSON_GetObjectCstr(jla
, "command");
3718 const char *sessid
= cJSON_GetObjectCstr(json
, "sessid");
3721 if (switch_live_array_create(context
, name
, channel_id
, &la
) == SWITCH_STATUS_SUCCESS
) {
3723 if (!strcasecmp(command
, "bootstrap")) {
3724 switch_live_array_bootstrap(la
, sessid
, channel_id
);
3726 if (la
->command_handler
) {
3727 la
->command_handler(la
, command
, sessid
, jla
, la
->user_data
);
3730 switch_live_array_destroy(&la
);
3741 * indent-tabs-mode:t
3746 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: