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 <switch_event.h>
39 #include "private/switch_core_pvt.h"
41 //#define SWITCH_EVENT_RECYCLE
42 #define DISPATCH_QUEUE_LEN 10000
43 //#define DEBUG_DISPATCH_QUEUES
45 /*! \brief A node to store binded events */
46 struct switch_event_node
{
47 /*! the id of the node */
49 /*! the event id enumeration to bind to */
50 switch_event_types_t event_id
;
51 /*! the event subclass to bind to for custom events */
53 /*! a callback function to execute when the event is triggered */
54 switch_event_callback_t callback
;
57 struct switch_event_node
*next
;
60 /*! \brief A registered custom event subclass */
61 struct switch_event_subclass
{
62 /*! the owner of the subclass */
64 /*! the subclass name */
66 /*! the subclass was reserved by a listener so it's ok for a module to reserve it still */
72 switch_event_channel_id_t ID
;
73 switch_thread_rwlock_t
*rwlock
;
75 switch_hash_t
*perm_hash
;
76 switch_hash_t
*lahash
;
77 switch_mutex_t
*lamutex
;
78 } event_channel_manager
;
80 #define MAX_DISPATCH_VAL 64
81 static unsigned int MAX_DISPATCH
= MAX_DISPATCH_VAL
;
82 static unsigned int SOFT_MAX_DISPATCH
= 0;
83 static char guess_ip_v4
[80] = "";
84 static char guess_ip_v6
[80] = "";
85 static switch_event_node_t
*EVENT_NODES
[SWITCH_EVENT_ALL
+ 1] = { NULL
};
86 static switch_thread_rwlock_t
*RWLOCK
= NULL
;
87 static switch_mutex_t
*BLOCK
= NULL
;
88 static switch_mutex_t
*POOL_LOCK
= NULL
;
89 static switch_memory_pool_t
*RUNTIME_POOL
= NULL
;
90 static switch_memory_pool_t
*THRUNTIME_POOL
= NULL
;
91 static switch_thread_t
*EVENT_DISPATCH_QUEUE_THREADS
[MAX_DISPATCH_VAL
] = { 0 };
92 static uint8_t EVENT_DISPATCH_QUEUE_RUNNING
[MAX_DISPATCH_VAL
] = { 0 };
93 static switch_queue_t
*EVENT_DISPATCH_QUEUE
= NULL
;
94 static switch_queue_t
*EVENT_CHANNEL_DISPATCH_QUEUE
= NULL
;
95 static switch_mutex_t
*EVENT_QUEUE_MUTEX
= NULL
;
96 static switch_mutex_t
*CUSTOM_HASH_MUTEX
= NULL
;
97 static switch_hash_t
*CUSTOM_HASH
= NULL
;
98 static int THREAD_COUNT
= 0;
99 static int DISPATCH_THREAD_COUNT
= 0;
100 static int EVENT_CHANNEL_DISPATCH_THREAD_COUNT
= 0;
101 static int EVENT_CHANNEL_DISPATCH_THREAD_STARTING
= 0;
102 static int SYSTEM_RUNNING
= 0;
103 static uint64_t EVENT_SEQUENCE_NR
= 0;
104 #ifdef SWITCH_EVENT_RECYCLE
105 static switch_queue_t
*EVENT_RECYCLE_QUEUE
= NULL
;
106 static switch_queue_t
*EVENT_HEADER_RECYCLE_QUEUE
= NULL
;
109 static void unsub_all_switch_event_channel(void);
111 static char *my_dup(const char *s
)
113 size_t len
= strlen(s
) + 1;
114 void *new = malloc(len
);
117 return (char *) memcpy(new, s
, len
);
121 #define ALLOC(size) malloc(size)
124 #define DUP(str) my_dup(str)
127 #define FREE(ptr) switch_safe_free(ptr)
130 /* make sure this is synced with the switch_event_types_t enum in switch_types.h
131 also never put any new ones before EVENT_ALL
133 static char *EVENT_NAMES
[] = {
142 "CHANNEL_HANGUP_COMPLETE",
144 "CHANNEL_EXECUTE_COMPLETE",
150 "CHANNEL_PROGRESS_MEDIA",
154 "CHANNEL_APPLICATION",
193 "PHONE_FEATURE_SUBSCRIBE",
201 "CLIENT_DISCONNECTED",
202 "SERVER_DISCONNECTED",
217 "CONFERENCE_DATA_QUERY",
227 static int switch_events_match(switch_event_t
*event
, switch_event_node_t
*node
)
231 if (node
->event_id
== SWITCH_EVENT_ALL
) {
234 if (!node
->subclass_name
) {
239 if (match
|| event
->event_id
== node
->event_id
) {
241 if (event
->subclass_name
&& node
->subclass_name
) {
242 if (!strncasecmp(node
->subclass_name
, "file:", 5)) {
244 if ((file_header
= switch_event_get_header(event
, "file")) != 0) {
245 match
= !strcmp(node
->subclass_name
+ 5, file_header
) ? 1 : 0;
247 } else if (!strncasecmp(node
->subclass_name
, "func:", 5)) {
249 if ((func_header
= switch_event_get_header(event
, "function")) != 0) {
250 match
= !strcmp(node
->subclass_name
+ 5, func_header
) ? 1 : 0;
252 } else if (event
->subclass_name
&& node
->subclass_name
) {
253 match
= !strcmp(event
->subclass_name
, node
->subclass_name
) ? 1 : 0;
255 } else if ((event
->subclass_name
&& !node
->subclass_name
) || (!event
->subclass_name
&& !node
->subclass_name
)) {
266 static void *SWITCH_THREAD_FUNC
switch_event_deliver_thread(switch_thread_t
*thread
, void *obj
)
268 switch_event_t
*event
= (switch_event_t
*) obj
;
270 switch_event_deliver(&event
);
275 static void switch_event_deliver_thread_pool(switch_event_t
**event
)
277 switch_thread_data_t
*td
;
279 td
= malloc(sizeof(*td
));
283 td
->func
= switch_event_deliver_thread
;
289 switch_thread_pool_launch_thread(&td
);
293 static void *SWITCH_THREAD_FUNC
switch_event_dispatch_thread(switch_thread_t
*thread
, void *obj
)
295 switch_queue_t
*queue
= (switch_queue_t
*) obj
;
298 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
300 DISPATCH_THREAD_COUNT
++;
302 for (my_id
= 0; my_id
< MAX_DISPATCH_VAL
; my_id
++) {
303 if (EVENT_DISPATCH_QUEUE_THREADS
[my_id
] == thread
) {
308 if ( my_id
>= MAX_DISPATCH_VAL
) {
309 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
313 EVENT_DISPATCH_QUEUE_RUNNING
[my_id
] = 1;
314 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
319 switch_event_t
*event
= NULL
;
321 if (!SYSTEM_RUNNING
) {
325 if (switch_queue_pop(queue
, &pop
) != SWITCH_STATUS_SUCCESS
) {
333 event
= (switch_event_t
*) pop
;
334 switch_event_deliver(&event
);
339 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
340 EVENT_DISPATCH_QUEUE_RUNNING
[my_id
] = 0;
342 DISPATCH_THREAD_COUNT
--;
343 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
345 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Dispatch Thread %d Ended.\n", my_id
);
350 static int PENDING
= 0;
352 static switch_status_t
switch_event_queue_dispatch_event(switch_event_t
**eventp
)
355 switch_event_t
*event
= *eventp
;
357 if (!SYSTEM_RUNNING
) {
358 return SWITCH_STATUS_FALSE
;
364 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
366 if (!PENDING
&& switch_queue_size(EVENT_DISPATCH_QUEUE
) > (unsigned int)(DISPATCH_QUEUE_LEN
* DISPATCH_THREAD_COUNT
)) {
367 if (SOFT_MAX_DISPATCH
+ 1 < MAX_DISPATCH
) {
373 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
376 if (SOFT_MAX_DISPATCH
+ 1 < MAX_DISPATCH
) {
377 switch_event_launch_dispatch_threads(SOFT_MAX_DISPATCH
+ 1);
380 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
382 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
386 switch_queue_push(EVENT_DISPATCH_QUEUE
, event
);
391 return SWITCH_STATUS_SUCCESS
;
394 SWITCH_DECLARE(void) switch_event_deliver(switch_event_t
**event
)
396 switch_event_types_t e
;
397 switch_event_node_t
*node
;
399 if (SYSTEM_RUNNING
) {
400 switch_thread_rwlock_rdlock(RWLOCK
);
401 for (e
= (*event
)->event_id
;; e
= SWITCH_EVENT_ALL
) {
402 for (node
= EVENT_NODES
[e
]; node
; node
= node
->next
) {
403 if (switch_events_match(*event
, node
)) {
404 (*event
)->bind_user_data
= node
->user_data
;
405 node
->callback(*event
);
409 if (e
== SWITCH_EVENT_ALL
) {
413 switch_thread_rwlock_unlock(RWLOCK
);
416 switch_event_destroy(event
);
419 SWITCH_DECLARE(switch_status_t
) switch_event_running(void)
421 return SYSTEM_RUNNING
? SWITCH_STATUS_SUCCESS
: SWITCH_STATUS_FALSE
;
424 SWITCH_DECLARE(const char *) switch_event_name(switch_event_types_t event
)
426 switch_assert(BLOCK
!= NULL
);
427 switch_assert(RUNTIME_POOL
!= NULL
);
429 return EVENT_NAMES
[event
];
432 SWITCH_DECLARE(switch_status_t
) switch_name_event(const char *name
, switch_event_types_t
*type
)
434 switch_event_types_t x
;
435 switch_assert(BLOCK
!= NULL
);
436 switch_assert(RUNTIME_POOL
!= NULL
);
438 for (x
= 0; x
<= SWITCH_EVENT_ALL
; x
++) {
439 if ((strlen(name
) > 13 && !strcasecmp(name
+ 13, EVENT_NAMES
[x
])) || !strcasecmp(name
, EVENT_NAMES
[x
])) {
441 return SWITCH_STATUS_SUCCESS
;
445 return SWITCH_STATUS_FALSE
;
448 SWITCH_DECLARE(switch_status_t
) switch_event_free_subclass_detailed(const char *owner
, const char *subclass_name
)
450 switch_event_subclass_t
*subclass
;
451 switch_status_t status
= SWITCH_STATUS_FALSE
;
453 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
455 switch_assert(RUNTIME_POOL
!= NULL
);
456 switch_assert(CUSTOM_HASH
!= NULL
);
458 if ((subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
))) {
459 if (!strcmp(owner
, subclass
->owner
)) {
460 switch_thread_rwlock_wrlock(RWLOCK
);
461 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Subclass reservation deleted for %s:%s\n", owner
, subclass_name
);
462 switch_core_hash_delete(CUSTOM_HASH
, subclass_name
);
463 FREE(subclass
->owner
);
464 FREE(subclass
->name
);
466 status
= SWITCH_STATUS_SUCCESS
;
467 switch_thread_rwlock_unlock(RWLOCK
);
469 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Subclass reservation %s inuse by listeners, detaching..\n", subclass_name
);
474 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
479 SWITCH_DECLARE(switch_status_t
) switch_event_reserve_subclass_detailed(const char *owner
, const char *subclass_name
)
481 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
482 switch_event_subclass_t
*subclass
;
484 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
486 switch_assert(RUNTIME_POOL
!= NULL
);
487 switch_assert(CUSTOM_HASH
!= NULL
);
489 if ((subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
))) {
490 /* a listener reserved it for us, now we can lock it so nobody else can have it */
491 if (subclass
->bind
) {
493 switch_goto_status(SWITCH_STATUS_SUCCESS
, end
);
495 switch_goto_status(SWITCH_STATUS_INUSE
, end
);
498 switch_zmalloc(subclass
, sizeof(*subclass
));
500 subclass
->owner
= DUP(owner
);
501 subclass
->name
= DUP(subclass_name
);
503 switch_core_hash_insert(CUSTOM_HASH
, subclass
->name
, subclass
);
507 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
512 SWITCH_DECLARE(void) switch_core_memory_reclaim_events(void)
514 #ifdef SWITCH_EVENT_RECYCLE
518 size
= switch_queue_size(EVENT_RECYCLE_QUEUE
);
520 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Returning %d recycled event(s) %d bytes\n", size
, (int) sizeof(switch_event_t
) * size
);
521 size
= switch_queue_size(EVENT_HEADER_RECYCLE_QUEUE
);
522 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Returning %d recycled event header(s) %d bytes\n",
523 size
, (int) sizeof(switch_event_header_t
) * size
);
525 while (switch_queue_trypop(EVENT_HEADER_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
528 while (switch_queue_trypop(EVENT_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
537 SWITCH_DECLARE(switch_status_t
) switch_event_shutdown(void)
541 switch_hash_index_t
*hi
;
545 if (switch_core_test_flag(SCF_MINIMAL
)) {
546 return SWITCH_STATUS_SUCCESS
;
549 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
551 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
553 unsub_all_switch_event_channel();
555 if (EVENT_CHANNEL_DISPATCH_QUEUE
) {
556 switch_queue_trypush(EVENT_CHANNEL_DISPATCH_QUEUE
, NULL
);
557 switch_queue_interrupt_all(EVENT_CHANNEL_DISPATCH_QUEUE
);
560 if (runtime
.events_use_dispatch
) {
561 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Stopping dispatch queues\n");
563 for(x
= 0; x
< (uint32_t)DISPATCH_THREAD_COUNT
; x
++) {
564 switch_queue_trypush(EVENT_DISPATCH_QUEUE
, NULL
);
568 switch_queue_interrupt_all(EVENT_DISPATCH_QUEUE
);
570 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Stopping dispatch threads\n");
572 for(x
= 0; x
< (uint32_t)DISPATCH_THREAD_COUNT
; x
++) {
574 switch_thread_join(&st
, EVENT_DISPATCH_QUEUE_THREADS
[x
]);
579 while (x
< 100 && THREAD_COUNT
) {
580 switch_yield(100000);
581 if (THREAD_COUNT
== last
) {
587 if (runtime
.events_use_dispatch
) {
589 switch_event_t
*event
= NULL
;
591 while (switch_queue_trypop(EVENT_DISPATCH_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
592 event
= (switch_event_t
*) pop
;
593 switch_event_destroy(&event
);
597 for (hi
= switch_core_hash_first(CUSTOM_HASH
); hi
; hi
= switch_core_hash_next(&hi
)) {
598 switch_event_subclass_t
*subclass
;
599 switch_core_hash_this(hi
, &var
, NULL
, &val
);
600 if ((subclass
= (switch_event_subclass_t
*) val
)) {
601 FREE(subclass
->name
);
602 FREE(subclass
->owner
);
607 switch_core_hash_destroy(&event_channel_manager
.lahash
);
608 switch_core_hash_destroy(&event_channel_manager
.hash
);
609 switch_core_hash_destroy(&event_channel_manager
.perm_hash
);
611 switch_core_hash_destroy(&CUSTOM_HASH
);
612 switch_core_memory_reclaim_events();
614 return SWITCH_STATUS_SUCCESS
;
617 static void check_dispatch(void)
619 if (!EVENT_DISPATCH_QUEUE
) {
620 switch_mutex_lock(BLOCK
);
622 if (!EVENT_DISPATCH_QUEUE
) {
623 switch_queue_create(&EVENT_DISPATCH_QUEUE
, DISPATCH_QUEUE_LEN
* MAX_DISPATCH
, THRUNTIME_POOL
);
624 switch_event_launch_dispatch_threads(1);
626 while (!THREAD_COUNT
) {
630 switch_mutex_unlock(BLOCK
);
636 SWITCH_DECLARE(void) switch_event_launch_dispatch_threads(uint32_t max
)
638 switch_threadattr_t
*thd_attr
;
641 uint32_t sanity
= 200;
643 switch_memory_pool_t
*pool
= RUNTIME_POOL
;
647 if (max
> MAX_DISPATCH
) {
651 if (max
< SOFT_MAX_DISPATCH
) {
655 for (index
= SOFT_MAX_DISPATCH
; index
< max
&& index
< MAX_DISPATCH
; index
++) {
656 if (EVENT_DISPATCH_QUEUE_THREADS
[index
]) {
660 switch_threadattr_create(&thd_attr
, pool
);
661 switch_threadattr_stacksize_set(thd_attr
, SWITCH_THREAD_STACKSIZE
);
662 switch_threadattr_priority_set(thd_attr
, SWITCH_PRI_REALTIME
);
663 switch_thread_create(&EVENT_DISPATCH_QUEUE_THREADS
[index
], thd_attr
, switch_event_dispatch_thread
, EVENT_DISPATCH_QUEUE
, pool
);
664 while(--sanity
&& !EVENT_DISPATCH_QUEUE_RUNNING
[index
]) switch_yield(10000);
667 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "Create event dispatch thread %d\n", index
);
669 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "Create additional event dispatch thread %d\n", index
);
674 SOFT_MAX_DISPATCH
= index
;
677 SWITCH_DECLARE(switch_status_t
) switch_event_init(switch_memory_pool_t
*pool
)
680 /* don't need any more dispatch threads than we have CPU's*/
681 MAX_DISPATCH
= (switch_core_cpu_count() / 2) + 1;
682 if (MAX_DISPATCH
< 2) {
686 switch_assert(pool
!= NULL
);
687 THRUNTIME_POOL
= RUNTIME_POOL
= pool
;
688 switch_thread_rwlock_create(&RWLOCK
, RUNTIME_POOL
);
689 switch_mutex_init(&BLOCK
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
690 switch_mutex_init(&POOL_LOCK
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
691 switch_mutex_init(&EVENT_QUEUE_MUTEX
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
692 switch_mutex_init(&CUSTOM_HASH_MUTEX
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
693 switch_core_hash_init(&CUSTOM_HASH
);
695 if (switch_core_test_flag(SCF_MINIMAL
)) {
696 return SWITCH_STATUS_SUCCESS
;
699 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_INFO
, "Activate Eventing Engine.\n");
701 switch_core_hash_init(&event_channel_manager
.lahash
);
702 switch_mutex_init(&event_channel_manager
.lamutex
, SWITCH_MUTEX_NESTED
, RUNTIME_POOL
);
704 switch_thread_rwlock_create(&event_channel_manager
.rwlock
, RUNTIME_POOL
);
705 switch_core_hash_init(&event_channel_manager
.hash
);
706 switch_core_hash_init(&event_channel_manager
.perm_hash
);
707 event_channel_manager
.ID
= 1;
709 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
711 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
713 //switch_threadattr_create(&thd_attr, pool);
714 switch_find_local_ip(guess_ip_v4
, sizeof(guess_ip_v4
), NULL
, AF_INET
);
715 switch_find_local_ip(guess_ip_v6
, sizeof(guess_ip_v6
), NULL
, AF_INET6
);
718 #ifdef SWITCH_EVENT_RECYCLE
719 switch_queue_create(&EVENT_RECYCLE_QUEUE
, 250000, THRUNTIME_POOL
);
720 switch_queue_create(&EVENT_HEADER_RECYCLE_QUEUE
, 250000, THRUNTIME_POOL
);
725 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
727 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
729 return SWITCH_STATUS_SUCCESS
;
732 SWITCH_DECLARE(switch_status_t
) switch_event_create_subclass_detailed(const char *file
, const char *func
, int line
,
733 switch_event_t
**event
, switch_event_types_t event_id
, const char *subclass_name
)
735 #ifdef SWITCH_EVENT_RECYCLE
741 if ((event_id
!= SWITCH_EVENT_CLONE
&& event_id
!= SWITCH_EVENT_CUSTOM
) && subclass_name
) {
742 return SWITCH_STATUS_GENERR
;
744 #ifdef SWITCH_EVENT_RECYCLE
745 if (EVENT_RECYCLE_QUEUE
&& switch_queue_trypop(EVENT_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
&& pop
) {
746 *event
= (switch_event_t
*) pop
;
749 *event
= ALLOC(sizeof(switch_event_t
));
750 switch_assert(*event
);
751 #ifdef SWITCH_EVENT_RECYCLE
755 memset(*event
, 0, sizeof(switch_event_t
));
757 if (event_id
== SWITCH_EVENT_REQUEST_PARAMS
|| event_id
== SWITCH_EVENT_CHANNEL_DATA
|| event_id
== SWITCH_EVENT_MESSAGE
) {
758 (*event
)->flags
|= EF_UNIQ_HEADERS
;
761 if (event_id
!= SWITCH_EVENT_CLONE
) {
762 (*event
)->event_id
= event_id
;
763 switch_event_prep_for_delivery_detailed(file
, func
, line
, *event
);
767 (*event
)->subclass_name
= DUP(subclass_name
);
768 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, "Event-Subclass", subclass_name
);
771 return SWITCH_STATUS_SUCCESS
;
774 SWITCH_DECLARE(switch_status_t
) switch_event_set_priority(switch_event_t
*event
, switch_priority_t priority
)
776 event
->priority
= priority
;
777 switch_event_add_header_string(event
, SWITCH_STACK_TOP
, "priority", switch_priority_name(priority
));
778 return SWITCH_STATUS_SUCCESS
;
781 SWITCH_DECLARE(switch_status_t
) switch_event_rename_header(switch_event_t
*event
, const char *header_name
, const char *new_header_name
)
783 switch_event_header_t
*hp
;
784 switch_ssize_t hlen
= -1;
785 unsigned long hash
= 0;
788 switch_assert(event
);
791 return SWITCH_STATUS_FALSE
;
794 hash
= switch_ci_hashfunc_default(header_name
, &hlen
);
796 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
797 if ((!hp
->hash
|| hash
== hp
->hash
) && !strcasecmp(hp
->name
, header_name
)) {
799 hp
->name
= DUP(new_header_name
);
801 hp
->hash
= switch_ci_hashfunc_default(hp
->name
, &hlen
);
806 return x
? SWITCH_STATUS_SUCCESS
: SWITCH_STATUS_FALSE
;
810 SWITCH_DECLARE(switch_event_header_t
*) switch_event_get_header_ptr(switch_event_t
*event
, const char *header_name
)
812 switch_event_header_t
*hp
;
813 switch_ssize_t hlen
= -1;
814 unsigned long hash
= 0;
816 switch_assert(event
);
821 hash
= switch_ci_hashfunc_default(header_name
, &hlen
);
823 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
824 if ((!hp
->hash
|| hash
== hp
->hash
) && !strcasecmp(hp
->name
, header_name
)) {
831 SWITCH_DECLARE(char *) switch_event_get_header_idx(switch_event_t
*event
, const char *header_name
, int idx
)
833 switch_event_header_t
*hp
;
835 if ((hp
= switch_event_get_header_ptr(event
, header_name
))) {
838 return hp
->array
[idx
];
845 } else if (!strcmp(header_name
, "_body")) {
852 SWITCH_DECLARE(char *) switch_event_get_body(switch_event_t
*event
)
854 return (event
? event
->body
: NULL
);
857 SWITCH_DECLARE(switch_status_t
) switch_event_del_header_val(switch_event_t
*event
, const char *header_name
, const char *val
)
859 switch_event_header_t
*hp
, *lp
= NULL
, *tp
;
860 switch_status_t status
= SWITCH_STATUS_FALSE
;
862 switch_ssize_t hlen
= -1;
863 unsigned long hash
= 0;
866 hash
= switch_ci_hashfunc_default(header_name
, &hlen
);
872 switch_assert(x
< 1000000);
874 if ((!hp
->hash
|| hash
== hp
->hash
) && !strcasecmp(header_name
, hp
->name
) && (zstr(val
) || !strcmp(hp
->value
, val
))) {
878 event
->headers
= hp
->next
;
880 if (hp
== event
->last_header
|| !hp
->next
) {
881 event
->last_header
= lp
;
888 for (i
= 0; i
< hp
->idx
; i
++) {
896 memset(hp
, 0, sizeof(*hp
));
897 #ifdef SWITCH_EVENT_RECYCLE
898 if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE
, hp
) != SWITCH_STATUS_SUCCESS
) {
904 status
= SWITCH_STATUS_SUCCESS
;
913 static switch_event_header_t
*new_header(const char *header_name
)
915 switch_event_header_t
*header
;
917 #ifdef SWITCH_EVENT_RECYCLE
919 if (EVENT_HEADER_RECYCLE_QUEUE
&& switch_queue_trypop(EVENT_HEADER_RECYCLE_QUEUE
, &pop
) == SWITCH_STATUS_SUCCESS
) {
920 header
= (switch_event_header_t
*) pop
;
923 header
= ALLOC(sizeof(*header
));
924 switch_assert(header
);
925 #ifdef SWITCH_EVENT_RECYCLE
929 memset(header
, 0, sizeof(*header
));
930 header
->name
= DUP(header_name
);
936 SWITCH_DECLARE(int) switch_event_add_array(switch_event_t
*event
, const char *var
, const char *val
)
945 if (strlen(val
) < 8) {
953 while((p
= strstr(p
, "|:"))) {
962 data
= strdup(val
+ 7);
964 len
= (sizeof(char *) * max
) + 1;
968 memset(array
, 0, len
);
970 switch_separate_string_string(data
, "|:", array
, max
);
972 for(i
= 0; i
< max
; i
++) {
973 switch_event_add_header_string(event
, SWITCH_STACK_PUSH
, var
, array
[i
]);
982 static switch_status_t
switch_event_base_add_header(switch_event_t
*event
, switch_stack_t stack
, const char *header_name
, char *data
)
984 switch_event_header_t
*header
= NULL
;
985 switch_ssize_t hlen
= -1;
986 int exists
= 0, fly
= 0;
989 char *real_header_name
= NULL
;
992 if (!strcmp(header_name
, "_body")) {
993 switch_event_set_body(event
, data
);
996 if ((index_ptr
= strchr(header_name
, '['))) {
998 index
= atoi(index_ptr
);
999 real_header_name
= DUP(header_name
);
1000 if ((index_ptr
= strchr(real_header_name
, '['))) {
1001 *index_ptr
++ = '\0';
1003 header_name
= real_header_name
;
1006 if (index_ptr
|| (stack
& SWITCH_STACK_PUSH
) || (stack
& SWITCH_STACK_UNSHIFT
)) {
1008 if (!(header
= switch_event_get_header_ptr(event
, header_name
)) && index_ptr
) {
1010 header
= new_header(header_name
);
1012 if (switch_test_flag(event
, EF_UNIQ_HEADERS
)) {
1013 switch_event_del_header(event
, header_name
);
1019 if (header
|| (header
= switch_event_get_header_ptr(event
, header_name
))) {
1022 if (index
> -1 && index
<= 4000) {
1023 if (index
< header
->idx
) {
1024 FREE(header
->array
[index
]);
1025 header
->array
[index
] = DUP(data
);
1030 m
= realloc(header
->array
, sizeof(char *) * (index
+ 1));
1033 for (i
= header
->idx
; i
< index
; i
++) {
1036 m
[index
] = DUP(data
);
1037 header
->idx
= index
+ 1;
1047 if ((stack
& SWITCH_STACK_PUSH
) || (stack
& SWITCH_STACK_UNSHIFT
)) {
1049 stack
&= ~(SWITCH_STACK_TOP
| SWITCH_STACK_BOTTOM
);
1061 switch_event_del_header(event
, header_name
);
1066 if (switch_test_flag(event
, EF_UNIQ_HEADERS
)) {
1067 switch_event_del_header(event
, header_name
);
1070 if (!strncmp(data
, "ARRAY::", 7)) {
1071 switch_event_add_array(event
, header_name
, data
);
1077 header
= new_header(header_name
);
1080 if ((stack
& SWITCH_STACK_PUSH
) || (stack
& SWITCH_STACK_UNSHIFT
)) {
1082 switch_size_t len
= 0;
1086 if (header
->value
&& !header
->idx
) {
1087 m
= malloc(sizeof(char *));
1089 m
[0] = header
->value
;
1090 header
->value
= NULL
;
1096 i
= header
->idx
+ 1;
1097 m
= realloc(header
->array
, sizeof(char *) * i
);
1100 if ((stack
& SWITCH_STACK_PUSH
)) {
1101 m
[header
->idx
] = data
;
1102 } else if ((stack
& SWITCH_STACK_UNSHIFT
)) {
1103 for (j
= header
->idx
; j
> 0; j
--) {
1114 for(j
= 0; j
< header
->idx
; j
++) {
1115 len
+= strlen(header
->array
[j
]) + 2;
1120 hv
= realloc(header
->value
, len
);
1124 if (header
->idx
> 1) {
1125 switch_snprintf(header
->value
, len
, "ARRAY::");
1127 *header
->value
= '\0';
1130 hv
+= strlen(header
->value
);
1131 for(j
= 0; j
< header
->idx
; j
++) {
1133 memcpy(hv
, "|:", 2);
1136 memcpy(hv
, header
->array
[j
], strlen(header
->array
[j
]));
1137 hv
+= strlen(header
->array
[j
]);
1143 switch_safe_free(header
->value
);
1144 header
->value
= data
;
1148 header
->hash
= switch_ci_hashfunc_default(header
->name
, &hlen
);
1150 if ((stack
& SWITCH_STACK_TOP
)) {
1151 header
->next
= event
->headers
;
1152 event
->headers
= header
;
1153 if (!event
->last_header
) {
1154 event
->last_header
= header
;
1157 if (event
->last_header
) {
1158 event
->last_header
->next
= header
;
1160 event
->headers
= header
;
1161 header
->next
= NULL
;
1163 event
->last_header
= header
;
1169 switch_safe_free(real_header_name
);
1171 return SWITCH_STATUS_SUCCESS
;
1174 SWITCH_DECLARE(switch_status_t
) switch_event_add_header(switch_event_t
*event
, switch_stack_t stack
, const char *header_name
, const char *fmt
, ...)
1181 ret
= switch_vasprintf(&data
, fmt
, ap
);
1185 return SWITCH_STATUS_MEMERR
;
1188 return switch_event_base_add_header(event
, stack
, header_name
, data
);
1191 SWITCH_DECLARE(switch_status_t
) switch_event_set_subclass_name(switch_event_t
*event
, const char *subclass_name
)
1193 if (!event
|| !subclass_name
)
1194 return SWITCH_STATUS_GENERR
;
1196 switch_safe_free(event
->subclass_name
);
1197 event
->subclass_name
= DUP(subclass_name
);
1198 switch_event_del_header(event
, "Event-Subclass");
1199 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Subclass", event
->subclass_name
);
1200 return SWITCH_STATUS_SUCCESS
;
1203 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
)
1206 return switch_event_base_add_header(event
, stack
, header_name
, (stack
& SWITCH_STACK_NODUP
) ? (char *)data
: DUP(data
));
1208 return SWITCH_STATUS_GENERR
;
1211 SWITCH_DECLARE(switch_status_t
) switch_event_set_body(switch_event_t
*event
, const char *body
)
1213 switch_safe_free(event
->body
);
1216 event
->body
= DUP(body
);
1219 return SWITCH_STATUS_SUCCESS
;
1222 SWITCH_DECLARE(switch_status_t
) switch_event_add_body(switch_event_t
*event
, const char *fmt
, ...)
1230 ret
= switch_vasprintf(&data
, fmt
, ap
);
1234 return SWITCH_STATUS_GENERR
;
1236 switch_safe_free(event
->body
);
1238 return SWITCH_STATUS_SUCCESS
;
1241 return SWITCH_STATUS_GENERR
;
1245 SWITCH_DECLARE(void) switch_event_destroy(switch_event_t
**event
)
1247 switch_event_t
*ep
= *event
;
1248 switch_event_header_t
*hp
, *this;
1251 for (hp
= ep
->headers
; hp
;) {
1257 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "INDEX WITH NO ARRAY WTF?? [%s][%s]\n", this->name
, this->value
);
1261 for (i
= 0; i
< this->idx
; i
++) {
1262 FREE(this->array
[i
]);
1272 #ifdef SWITCH_EVENT_RECYCLE
1273 if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE
, this) != SWITCH_STATUS_SUCCESS
) {
1283 FREE(ep
->subclass_name
);
1284 #ifdef SWITCH_EVENT_RECYCLE
1285 if (switch_queue_trypush(EVENT_RECYCLE_QUEUE
, ep
) != SWITCH_STATUS_SUCCESS
) {
1297 SWITCH_DECLARE(void) switch_event_merge(switch_event_t
*event
, switch_event_t
*tomerge
)
1299 switch_event_header_t
*hp
;
1301 switch_assert(tomerge
&& event
);
1303 for (hp
= tomerge
->headers
; hp
; hp
= hp
->next
) {
1307 for(i
= 0; i
< hp
->idx
; i
++) {
1308 switch_event_add_header_string(event
, SWITCH_STACK_PUSH
, hp
->name
, hp
->array
[i
]);
1311 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, hp
->name
, hp
->value
);
1316 SWITCH_DECLARE(switch_status_t
) switch_event_dup(switch_event_t
**event
, switch_event_t
*todup
)
1318 switch_event_header_t
*hp
;
1320 if (switch_event_create_subclass(event
, SWITCH_EVENT_CLONE
, todup
->subclass_name
) != SWITCH_STATUS_SUCCESS
) {
1321 return SWITCH_STATUS_GENERR
;
1324 (*event
)->event_id
= todup
->event_id
;
1325 (*event
)->event_user_data
= todup
->event_user_data
;
1326 (*event
)->bind_user_data
= todup
->bind_user_data
;
1327 (*event
)->flags
= todup
->flags
;
1328 for (hp
= todup
->headers
; hp
; hp
= hp
->next
) {
1329 if (todup
->subclass_name
&& !strcmp(hp
->name
, "Event-Subclass")) {
1335 for (i
= 0; i
< hp
->idx
; i
++) {
1336 switch_event_add_header_string(*event
, SWITCH_STACK_PUSH
, hp
->name
, hp
->array
[i
]);
1339 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, hp
->name
, hp
->value
);
1344 (*event
)->body
= DUP(todup
->body
);
1347 (*event
)->key
= todup
->key
;
1349 return SWITCH_STATUS_SUCCESS
;
1353 SWITCH_DECLARE(switch_status_t
) switch_event_dup_reply(switch_event_t
**event
, switch_event_t
*todup
)
1355 switch_event_header_t
*hp
;
1356 char hname
[1024] = "";
1359 if (switch_event_create_subclass(event
, SWITCH_EVENT_CLONE
, todup
->subclass_name
) != SWITCH_STATUS_SUCCESS
) {
1360 return SWITCH_STATUS_GENERR
;
1363 (*event
)->event_id
= todup
->event_id
;
1364 (*event
)->event_user_data
= todup
->event_user_data
;
1365 (*event
)->bind_user_data
= todup
->bind_user_data
;
1366 (*event
)->flags
= todup
->flags
;
1368 for (hp
= todup
->headers
; hp
; hp
= hp
->next
) {
1369 char *name
= hp
->name
, *value
= hp
->value
;
1371 if (todup
->subclass_name
&& !strcmp(hp
->name
, "Event-Subclass")) {
1375 if (!strncasecmp(hp
->name
, "from_", 5)) {
1377 switch_snprintf(hname
, sizeof(hname
), "to_%s", p
);
1379 } else if (!strncasecmp(hp
->name
, "to_", 3)) {
1381 switch_snprintf(hname
, sizeof(hname
), "from_%s", p
);
1383 } else if (!strcasecmp(name
, "to")) {
1385 } else if (!strcasecmp(name
, "from")) {
1391 for (i
= 0; i
< hp
->idx
; i
++) {
1392 switch_event_add_header_string(*event
, SWITCH_STACK_PUSH
, name
, hp
->array
[i
]);
1395 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, name
, value
);
1399 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, "replying", "true");
1402 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, "orig_body", todup
->body
);
1405 (*event
)->key
= todup
->key
;
1407 return SWITCH_STATUS_SUCCESS
;
1410 #define SWITCH_SERIALIZED_EVENT_MAP "S(iiisss)A(S(ss))"
1412 SWITCH_DECLARE(switch_status_t
) switch_event_binary_deserialize(switch_event_t
**eventp
, void **data
, switch_size_t len
, switch_bool_t destroy
)
1414 switch_event_t
*event
;
1416 switch_serial_event_t e
;
1417 switch_serial_event_header_t sh
;
1420 switch_event_create(&event
, SWITCH_EVENT_CLONE
);
1421 switch_assert(event
);
1423 tn
= tpl_map(SWITCH_SERIALIZED_EVENT_MAP
, &e
, &sh
);
1426 how
|= TPL_EXCESS_OK
;
1429 tpl_load(tn
, how
, data
, len
);
1433 event
->event_id
= e
.event_id
;
1434 event
->priority
= e
.priority
;
1435 event
->flags
= e
.flags
;
1437 event
->owner
= e
.owner
;
1438 event
->subclass_name
= e
.subclass_name
;
1439 event
->body
= e
.body
;
1442 while(tpl_unpack(tn
, 1)) {
1443 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, sh
.name
, sh
.value
);
1456 return SWITCH_STATUS_SUCCESS
;
1460 SWITCH_DECLARE(switch_status_t
) switch_event_binary_serialize(switch_event_t
*event
, void **data
, switch_size_t
*len
)
1463 switch_serial_event_t e
;
1464 switch_serial_event_header_t sh
;
1465 switch_event_header_t
*eh
;
1468 e
.event_id
= event
->event_id
;
1469 e
.priority
= event
->priority
;
1470 e
.flags
= event
->flags
;
1472 e
.owner
= event
->owner
;
1473 e
.subclass_name
= event
->subclass_name
;
1474 e
.body
= event
->body
;
1476 tn
= tpl_map(SWITCH_SERIALIZED_EVENT_MAP
, &e
, &sh
);
1480 for (eh
= event
->headers
; eh
; eh
= eh
->next
) {
1481 if (eh
->idx
) continue; // no arrays yet
1484 sh
.value
= eh
->value
;
1490 how
|= TPL_PREALLOCD
;
1493 tpl_dump(tn
, how
, data
, len
);
1497 return SWITCH_STATUS_SUCCESS
;
1501 SWITCH_DECLARE(switch_status_t
) switch_event_serialize(switch_event_t
*event
, char **str
, switch_bool_t encode
)
1503 switch_size_t len
= 0;
1504 switch_event_header_t
*hp
;
1505 switch_size_t llen
= 0, dlen
= 0, blocksize
= 512, encode_len
= 1536, new_len
= 0;
1507 char *encode_buf
= NULL
; /* used for url encoding of variables to make sure unsafe things stay out of the serialized copy */
1511 dlen
= blocksize
* 2;
1513 if (!(buf
= malloc(dlen
))) {
1517 /* go ahead and give ourselves some space to work with, should save a few reallocs */
1518 if (!(encode_buf
= malloc(encode_len
))) {
1522 /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "hit serialized!.\n"); */
1523 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
1525 * grab enough memory to store 3x the string (url encode takes one char and turns it into %XX)
1526 * so we could end up with a string that is 3 times the originals length, unlikely but rather
1527 * be safe than destroy the string, also add one for the null. And try to be smart about using
1528 * the memory, allocate and only reallocate if we need more. This avoids an alloc, free CPU
1535 for(i
= 0; i
< hp
->idx
; i
++) {
1536 new_len
+= (strlen(hp
->array
[i
]) * 3) + 1;
1539 new_len
= (strlen(hp
->value
) * 3) + 1;
1542 if (encode_len
< new_len
) {
1545 /* keep track of the size of our allocation */
1546 encode_len
= new_len
;
1548 if (!(tmp
= realloc(encode_buf
, encode_len
))) {
1555 /* handle any bad things in the string like newlines : etc that screw up the serialized format */
1559 switch_url_encode(hp
->value
, encode_buf
, encode_len
);
1561 switch_snprintf(encode_buf
, encode_len
, "[%s]", hp
->value
);
1565 llen
= strlen(hp
->name
) + strlen(encode_buf
) + 8;
1567 if ((len
+ llen
) > dlen
) {
1569 dlen
+= (blocksize
+ (len
+ llen
));
1570 if (!(buf
= realloc(buf
, dlen
))) {
1576 switch_snprintf(buf
+ len
, dlen
- len
, "%s: %s\n", hp
->name
, *encode_buf
== '\0' ? "_undef_" : encode_buf
);
1580 /* we are done with the memory we used for encoding, give it back */
1581 switch_safe_free(encode_buf
);
1584 int blen
= (int) strlen(event
->body
);
1593 if ((len
+ llen
) > dlen
) {
1595 dlen
+= (blocksize
+ (len
+ llen
));
1596 if (!(buf
= realloc(buf
, dlen
))) {
1603 switch_snprintf(buf
+ len
, dlen
- len
, "Content-Length: %d\n\n%s", blen
, event
->body
);
1605 switch_snprintf(buf
+ len
, dlen
- len
, "\n");
1608 switch_snprintf(buf
+ len
, dlen
- len
, "\n");
1613 return SWITCH_STATUS_SUCCESS
;
1616 SWITCH_DECLARE(switch_status_t
) switch_event_create_array_pair(switch_event_t
**event
, char **names
, char **vals
, int len
)
1621 switch_event_create(event
, SWITCH_EVENT_CLONE
);
1623 for (r
= 0; r
< len
; r
++) {
1624 val
= switch_str_nil(vals
[r
]);
1631 switch_event_add_header_string(*event
, SWITCH_STACK_BOTTOM
, name
, val
);
1634 return SWITCH_STATUS_SUCCESS
;
1638 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
)
1640 char *vdata
, *vdatap
= NULL
;
1641 char *end
, *check_a
, *check_b
;
1642 switch_event_t
*e
= *event
;
1643 char *var_array
[1024] = { 0 };
1645 char *next
= NULL
, *vnext
= NULL
;
1648 vdatap
= strdup(data
);
1654 end
= switch_find_end_paren(vdata
, a
, b
);
1658 while (check_a
&& (check_b
= switch_strchr_strict(check_a
, a
, " "))) {
1659 if ((check_b
= switch_find_end_paren(check_b
, a
, b
))) {
1664 if (check_a
) end
= check_a
;
1674 return SWITCH_STATUS_FALSE
;
1678 switch_event_create_plain(&e
, SWITCH_EVENT_CHANNEL_DATA
);
1679 e
->flags
|= EF_UNIQ_HEADERS
;
1689 if ((pnext
= switch_strchr_strict(next
, a
, " "))) {
1693 vnext
= switch_find_end_paren(next
, a
, b
);
1699 if (*vdata
== '^' && *(vdata
+ 1) == '^') {
1705 if ((var_count
= switch_separate_string(vdata
, c
, var_array
, (sizeof(var_array
) / sizeof(var_array
[0]))))) {
1707 for (x
= 0; x
< var_count
; x
++) {
1708 char *inner_var_array
[2] = { 0 };
1709 int inner_var_count
;
1711 if ((inner_var_count
= switch_separate_string(var_array
[x
], '=',
1712 inner_var_array
, (sizeof(inner_var_array
) / sizeof(inner_var_array
[0])))) == 2) {
1713 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG1
, "Parsing variable [%s]=[%s]\n", inner_var_array
[0], inner_var_array
[1]);
1714 switch_event_add_header_string(e
, SWITCH_STACK_BOTTOM
, inner_var_array
[0], inner_var_array
[1]);
1731 *new_data
= strdup(end
);
1737 return SWITCH_STATUS_SUCCESS
;
1743 SWITCH_DECLARE(switch_status_t
) switch_event_create_json(switch_event_t
**event
, const char *json
)
1745 switch_event_t
*new_event
;
1749 if (!(cj
= cJSON_Parse(json
))) {
1750 return SWITCH_STATUS_FALSE
;
1753 if (switch_event_create(&new_event
, SWITCH_EVENT_CLONE
) != SWITCH_STATUS_SUCCESS
) {
1755 return SWITCH_STATUS_FALSE
;
1758 for (cjp
= cj
->child
; cjp
; cjp
= cjp
->next
) {
1759 char *name
= cjp
->string
;
1760 char *value
= cjp
->valuestring
;
1762 if (name
&& value
) {
1763 if (!strcasecmp(name
, "_body")) {
1764 switch_event_add_body(new_event
, value
, SWITCH_VA_NONE
);
1766 if (!strcasecmp(name
, "event-name")) {
1767 switch_event_del_header(new_event
, "event-name");
1768 switch_name_event(value
, &new_event
->event_id
);
1771 switch_event_add_header_string(new_event
, SWITCH_STACK_BOTTOM
, name
, value
);
1775 if (cjp
->type
== cJSON_Array
) {
1776 int i
, x
= cJSON_GetArraySize(cjp
);
1778 for (i
= 0; i
< x
; i
++) {
1779 cJSON
*item
= cJSON_GetArrayItem(cjp
, i
);
1781 if (item
&& item
->type
== cJSON_String
&& item
->valuestring
) {
1782 switch_event_add_header_string(new_event
, SWITCH_STACK_PUSH
, name
, item
->valuestring
);
1791 return SWITCH_STATUS_SUCCESS
;
1794 SWITCH_DECLARE(switch_status_t
) switch_event_serialize_json_obj(switch_event_t
*event
, cJSON
**json
)
1796 switch_event_header_t
*hp
;
1799 cj
= cJSON_CreateObject();
1801 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
1803 cJSON
*a
= cJSON_CreateArray();
1806 for(i
= 0; i
< hp
->idx
; i
++) {
1807 cJSON_AddItemToArray(a
, cJSON_CreateString(hp
->array
[i
]));
1810 cJSON_AddItemToObject(cj
, hp
->name
, a
);
1813 cJSON_AddItemToObject(cj
, hp
->name
, cJSON_CreateString(hp
->value
));
1818 int blen
= (int) strlen(event
->body
);
1821 switch_snprintf(tmp
, sizeof(tmp
), "%d", blen
);
1823 cJSON_AddItemToObject(cj
, "Content-Length", cJSON_CreateString(tmp
));
1824 cJSON_AddItemToObject(cj
, "_body", cJSON_CreateString(event
->body
));
1829 return SWITCH_STATUS_SUCCESS
;
1832 SWITCH_DECLARE(switch_status_t
) switch_event_serialize_json(switch_event_t
*event
, char **str
)
1838 if (switch_event_serialize_json_obj(event
, &cj
) == SWITCH_STATUS_SUCCESS
) {
1839 *str
= cJSON_PrintUnformatted(cj
);
1842 return SWITCH_STATUS_SUCCESS
;
1845 return SWITCH_STATUS_FALSE
;
1848 static switch_xml_t
add_xml_header(switch_xml_t xml
, char *name
, char *value
, int offset
)
1850 switch_xml_t header
= switch_xml_add_child_d(xml
, name
, offset
);
1853 switch_size_t encode_len
= (strlen(value
) * 3) + 1;
1854 char *encode_buf
= malloc(encode_len
);
1856 switch_assert(encode_buf
);
1858 memset(encode_buf
, 0, encode_len
);
1859 switch_url_encode((char *) value
, encode_buf
, encode_len
);
1860 switch_xml_set_txt_d(header
, encode_buf
);
1867 SWITCH_DECLARE(switch_xml_t
) switch_event_xmlize(switch_event_t
*event
, const char *fmt
,...)
1869 switch_event_header_t
*hp
;
1870 char *data
= NULL
, *body
= NULL
;
1872 switch_xml_t xml
= NULL
;
1875 switch_xml_t xheaders
= NULL
;
1877 if (!(xml
= switch_xml_new("event"))) {
1883 #ifdef HAVE_VASPRINTF
1884 ret
= vasprintf(&data
, fmt
, ap
);
1886 data
= (char *) malloc(2048);
1891 ret
= vsnprintf(data
, 2048, fmt
, ap
);
1895 #ifndef HAVE_VASPRINTF
1902 if ((xheaders
= switch_xml_add_child_d(xml
, "headers", off
++))) {
1904 for (hp
= event
->headers
; hp
; hp
= hp
->next
) {
1908 for (i
= 0; i
< hp
->idx
; i
++) {
1909 add_xml_header(xheaders
, hp
->name
, hp
->array
[i
], hoff
++);
1912 add_xml_header(xheaders
, hp
->name
, hp
->value
, hoff
++);
1919 } else if (event
->body
) {
1924 int blen
= (int) strlen(body
);
1926 switch_snprintf(blena
, sizeof(blena
), "%d", blen
);
1928 switch_xml_t xbody
= NULL
;
1930 add_xml_header(xml
, "Content-Length", blena
, off
++);
1931 if ((xbody
= switch_xml_add_child_d(xml
, "body", off
++))) {
1932 switch_xml_set_txt_d(xbody
, body
);
1944 SWITCH_DECLARE(void) switch_event_prep_for_delivery_detailed(const char *file
, const char *func
, int line
, switch_event_t
*event
)
1946 switch_time_exp_t tm
;
1948 switch_size_t retsize
;
1949 switch_time_t ts
= switch_micro_time_now();
1952 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
1953 seq
= ++EVENT_SEQUENCE_NR
;
1954 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
1957 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Name", switch_event_name(event
->event_id
));
1958 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Core-UUID", switch_core_get_uuid());
1959 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-Hostname", switch_core_get_hostname());
1960 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-Switchname", switch_core_get_switchname());
1961 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-IPv4", guess_ip_v4
);
1962 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "FreeSWITCH-IPv6", guess_ip_v6
);
1964 switch_time_exp_lt(&tm
, ts
);
1965 switch_strftime_nocheck(date
, &retsize
, sizeof(date
), "%Y-%m-%d %T", &tm
);
1966 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Date-Local", date
);
1967 switch_rfc822_date(date
, ts
);
1968 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Date-GMT", date
);
1969 switch_event_add_header(event
, SWITCH_STACK_BOTTOM
, "Event-Date-Timestamp", "%" SWITCH_UINT64_T_FMT
, (uint64_t) ts
);
1970 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Calling-File", switch_cut_path(file
));
1971 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, "Event-Calling-Function", func
);
1972 switch_event_add_header(event
, SWITCH_STACK_BOTTOM
, "Event-Calling-Line-Number", "%d", line
);
1973 switch_event_add_header(event
, SWITCH_STACK_BOTTOM
, "Event-Sequence", "%" SWITCH_UINT64_T_FMT
, seq
);
1978 SWITCH_DECLARE(switch_status_t
) switch_event_fire_detailed(const char *file
, const char *func
, int line
, switch_event_t
**event
, void *user_data
)
1981 switch_assert(BLOCK
!= NULL
);
1982 switch_assert(RUNTIME_POOL
!= NULL
);
1983 switch_assert(EVENT_QUEUE_MUTEX
!= NULL
);
1984 switch_assert(RUNTIME_POOL
!= NULL
);
1986 if (SYSTEM_RUNNING
<= 0) {
1987 /* sorry we're closed */
1988 switch_event_destroy(event
);
1989 return SWITCH_STATUS_SUCCESS
;
1993 (*event
)->event_user_data
= user_data
;
1998 if (runtime
.events_use_dispatch
) {
2001 if (switch_event_queue_dispatch_event(event
) != SWITCH_STATUS_SUCCESS
) {
2002 switch_event_destroy(event
);
2003 return SWITCH_STATUS_FALSE
;
2006 switch_event_deliver_thread_pool(event
);
2009 return SWITCH_STATUS_SUCCESS
;
2012 SWITCH_DECLARE(switch_status_t
) switch_event_get_custom_events(switch_console_callback_match_t
**matches
)
2014 switch_hash_index_t
*hi
= NULL
;
2019 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
2021 for (hi
= switch_core_hash_first(CUSTOM_HASH
); hi
; hi
= switch_core_hash_next(&hi
)) {
2022 switch_core_hash_this(hi
, &var
, NULL
, &val
);
2023 switch_console_push_match(matches
, (const char *) var
);
2027 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
2029 return x
? SWITCH_STATUS_SUCCESS
: SWITCH_STATUS_FALSE
;
2032 SWITCH_DECLARE(switch_status_t
) switch_event_bind_removable(const char *id
, switch_event_types_t event
, const char *subclass_name
,
2033 switch_event_callback_t callback
, void *user_data
, switch_event_node_t
**node
)
2035 switch_event_node_t
*event_node
;
2036 switch_event_subclass_t
*subclass
= NULL
;
2038 switch_assert(BLOCK
!= NULL
);
2039 switch_assert(RUNTIME_POOL
!= NULL
);
2045 if (subclass_name
) {
2046 switch_mutex_lock(CUSTOM_HASH_MUTEX
);
2048 if (!(subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
))) {
2049 switch_event_reserve_subclass_detailed(id
, subclass_name
);
2050 subclass
= switch_core_hash_find(CUSTOM_HASH
, subclass_name
);
2054 switch_mutex_unlock(CUSTOM_HASH_MUTEX
);
2057 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Could not reserve subclass. '%s'\n", subclass_name
);
2058 return SWITCH_STATUS_FALSE
;
2062 if (event
<= SWITCH_EVENT_ALL
) {
2063 switch_zmalloc(event_node
, sizeof(*event_node
));
2064 switch_thread_rwlock_wrlock(RWLOCK
);
2065 switch_mutex_lock(BLOCK
);
2066 /* <LOCKED> ----------------------------------------------- */
2067 event_node
->id
= DUP(id
);
2068 event_node
->event_id
= event
;
2069 if (subclass_name
) {
2070 event_node
->subclass_name
= DUP(subclass_name
);
2072 event_node
->callback
= callback
;
2073 event_node
->user_data
= user_data
;
2075 if (EVENT_NODES
[event
]) {
2076 event_node
->next
= EVENT_NODES
[event
];
2079 EVENT_NODES
[event
] = event_node
;
2080 switch_mutex_unlock(BLOCK
);
2081 switch_thread_rwlock_unlock(RWLOCK
);
2082 /* </LOCKED> ----------------------------------------------- */
2088 return SWITCH_STATUS_SUCCESS
;
2091 return SWITCH_STATUS_MEMERR
;
2095 SWITCH_DECLARE(switch_status_t
) switch_event_bind(const char *id
, switch_event_types_t event
, const char *subclass_name
,
2096 switch_event_callback_t callback
, void *user_data
)
2098 return switch_event_bind_removable(id
, event
, subclass_name
, callback
, user_data
, NULL
);
2102 SWITCH_DECLARE(switch_status_t
) switch_event_unbind_callback(switch_event_callback_t callback
)
2104 switch_event_node_t
*n
, *np
, *lnp
= NULL
;
2105 switch_status_t status
= SWITCH_STATUS_FALSE
;
2108 switch_thread_rwlock_wrlock(RWLOCK
);
2109 switch_mutex_lock(BLOCK
);
2110 /* <LOCKED> ----------------------------------------------- */
2111 for (id
= 0; id
<= SWITCH_EVENT_ALL
; id
++) {
2114 for (np
= EVENT_NODES
[id
]; np
;) {
2117 if (n
->callback
== callback
) {
2119 lnp
->next
= n
->next
;
2121 EVENT_NODES
[n
->event_id
] = n
->next
;
2124 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Event Binding deleted for %s:%s\n", n
->id
, switch_event_name(n
->event_id
));
2125 FREE(n
->subclass_name
);
2128 status
= SWITCH_STATUS_SUCCESS
;
2134 switch_mutex_unlock(BLOCK
);
2135 switch_thread_rwlock_unlock(RWLOCK
);
2136 /* </LOCKED> ----------------------------------------------- */
2143 SWITCH_DECLARE(switch_status_t
) switch_event_unbind(switch_event_node_t
**node
)
2145 switch_event_node_t
*n
, *np
, *lnp
= NULL
;
2146 switch_status_t status
= SWITCH_STATUS_FALSE
;
2154 switch_thread_rwlock_wrlock(RWLOCK
);
2155 switch_mutex_lock(BLOCK
);
2156 /* <LOCKED> ----------------------------------------------- */
2157 for (np
= EVENT_NODES
[n
->event_id
]; np
; np
= np
->next
) {
2160 lnp
->next
= n
->next
;
2162 EVENT_NODES
[n
->event_id
] = n
->next
;
2164 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Event Binding deleted for %s:%s\n", n
->id
, switch_event_name(n
->event_id
));
2165 FREE(n
->subclass_name
);
2169 status
= SWITCH_STATUS_SUCCESS
;
2174 switch_mutex_unlock(BLOCK
);
2175 switch_thread_rwlock_unlock(RWLOCK
);
2176 /* </LOCKED> ----------------------------------------------- */
2181 SWITCH_DECLARE(switch_status_t
) switch_event_create_pres_in_detailed(char *file
, char *func
, int line
,
2182 const char *proto
, const char *login
,
2183 const char *from
, const char *from_domain
,
2184 const char *status
, const char *event_type
,
2185 const char *alt_event_type
, int event_count
,
2186 const char *unique_id
, const char *channel_state
,
2187 const char *answer_state
, const char *call_direction
)
2189 switch_event_t
*pres_event
;
2191 if (switch_event_create_subclass(&pres_event
, SWITCH_EVENT_PRESENCE_IN
, SWITCH_EVENT_SUBCLASS_ANY
) == SWITCH_STATUS_SUCCESS
) {
2192 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "proto", proto
);
2193 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "login", login
);
2194 switch_event_add_header(pres_event
, SWITCH_STACK_TOP
, "from", "%s@%s", from
, from_domain
);
2195 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "status", status
);
2196 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "event_type", event_type
);
2197 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "alt_event_type", alt_event_type
);
2198 switch_event_add_header(pres_event
, SWITCH_STACK_TOP
, "event_count", "%d", event_count
);
2199 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "unique-id", alt_event_type
);
2200 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "channel-state", channel_state
);
2201 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "answer-state", answer_state
);
2202 switch_event_add_header_string(pres_event
, SWITCH_STACK_TOP
, "presence-call-direction", call_direction
);
2203 switch_event_fire_detailed(file
, func
, line
, &pres_event
, NULL
);
2204 return SWITCH_STATUS_SUCCESS
;
2206 return SWITCH_STATUS_MEMERR
;
2209 #define resize(l) {\
2211 olen += (len + l + block);\
2213 if ((dp = realloc(data, olen))) {\
2216 memset(c, 0, olen - cpos);\
2219 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)
2222 char *data
, *indup
, *endof_indup
;
2223 size_t sp
= 0, len
= 0, olen
= 0, vtype
= 0, br
= 0, cpos
, block
= 128;
2224 const char *sub_val
= NULL
;
2225 char *cloned_sub_val
= NULL
, *expanded_sub_val
= NULL
;
2226 char *func_val
= NULL
;
2228 char *gvar
= NULL
, *sb
= NULL
;
2238 nv
= switch_string_var_check_const(in
) || switch_string_has_escaped_data(in
);
2245 olen
= strlen(in
) + 1;
2247 endof_indup
= end_of_p(indup
) + 1;
2249 if ((data
= malloc(olen
))) {
2250 memset(data
, 0, olen
);
2252 for (p
= indup
; p
&& p
< endof_indup
&& *p
; p
++) {
2257 if (*(p
+ 1) == '$') {
2260 if (*(p
+ 1) == '$') {
2263 } else if (*(p
+ 1) == '\'') {
2266 } else if (*(p
+ 1) == '\\') {
2267 if (len
+ 1 >= olen
) {
2277 if (*p
== '$' && !nv
) {
2278 if (*(p
+ 1) == '$') {
2284 if (*(p
+ 1) == '{') {
2285 vtype
= global
? 3 : 1;
2295 if (len
+ 1 >= olen
) {
2306 char *s
= p
, *e
, *vname
, *vval
= NULL
;
2311 if ((vtype
== 1 || vtype
== 3) && *s
== '{') {
2319 if (br
== 1 && *e
== '}') {
2326 if (e
!= s
&& *e
== '{') {
2328 } else if (br
> 1 && *e
== '}') {
2335 p
= e
> endof_indup
? endof_indup
: e
;
2338 for(sb
= vname
; sb
&& *sb
; sb
++) {
2342 } else if (*sb
== '(') {
2361 } else if (br
> 1 && *e
== ')') {
2363 } else if (br
== 1 && *e
== ')') {
2373 if (vtype
== 1 || vtype
== 3) {
2374 char *expanded
= NULL
;
2380 if ((expanded
= switch_event_expand_headers_check(event
, (char *) vname
, var_list
, api_list
, recur
+1)) == vname
) {
2385 if ((ptr
= strchr(vname
, ':'))) {
2388 if ((ptr
= strchr(ptr
, ':'))) {
2390 ooffset
= atoi(ptr
);
2394 if ((ptr
= strchr(vname
, '[')) && strchr(ptr
, ']')) {
2399 if (vtype
== 3 || !(sub_val
= switch_event_get_header_idx(event
, vname
, idx
))) {
2400 switch_safe_free(gvar
);
2401 if ((gvar
= switch_core_get_variable_dup(vname
))) {
2405 if (var_list
&& !switch_event_check_permission_list(var_list
, vname
)) {
2406 sub_val
= "<Variable Expansion Permission Denied>";
2410 if ((expanded_sub_val
= switch_event_expand_headers_check(event
, sub_val
, var_list
, api_list
, recur
+1)) == sub_val
) {
2411 expanded_sub_val
= NULL
;
2413 sub_val
= expanded_sub_val
;
2418 if (offset
|| ooffset
) {
2419 cloned_sub_val
= strdup(sub_val
);
2420 switch_assert(cloned_sub_val
);
2421 sub_val
= cloned_sub_val
;
2426 } else if ((size_t) abs(offset
) <= strlen(sub_val
)) {
2427 sub_val
= cloned_sub_val
+ (strlen(cloned_sub_val
) + offset
);
2430 if (ooffset
> 0 && (size_t) ooffset
< strlen(sub_val
)) {
2431 if ((ptr
= (char *) sub_val
+ ooffset
)) {
2437 switch_safe_free(expanded
);
2439 switch_stream_handle_t stream
= { 0 };
2440 char *expanded
= NULL
;
2442 SWITCH_STANDARD_STREAM(stream
);
2445 char *expanded_vname
= NULL
;
2447 if ((expanded_vname
= switch_event_expand_headers_check(event
, (char *) vname
, var_list
, api_list
, recur
+1)) == vname
) {
2448 expanded_vname
= NULL
;
2450 vname
= expanded_vname
;
2453 if ((expanded
= switch_event_expand_headers_check(event
, vval
, var_list
, api_list
, recur
+1)) == vval
) {
2459 if (!switch_core_test_flag(SCF_API_EXPANSION
) || (api_list
&& !switch_event_check_permission_list(api_list
, vname
))) {
2461 sub_val
= "<API execute Permission Denied>";
2463 if (switch_api_execute(vname
, vval
, NULL
, &stream
) == SWITCH_STATUS_SUCCESS
) {
2464 func_val
= stream
.data
;
2471 switch_safe_free(expanded
);
2472 switch_safe_free(expanded_vname
);
2475 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "Memory Error!\n");
2481 if ((nlen
= sub_val
? strlen(sub_val
) : 0)) {
2482 if (len
+ nlen
>= olen
) {
2491 switch_safe_free(func_val
);
2492 switch_safe_free(cloned_sub_val
);
2493 switch_safe_free(expanded_sub_val
);
2501 if (len
+ 1 >= olen
) {
2513 if (len
+ 1 >= olen
) {
2523 switch_safe_free(gvar
);
2528 SWITCH_DECLARE(char *) switch_event_build_param_string(switch_event_t
*event
, const char *prefix
, switch_hash_t
*vars_map
)
2530 switch_stream_handle_t stream
= { 0 };
2531 switch_size_t encode_len
= 1024, new_len
= 0;
2532 char *encode_buf
= NULL
;
2533 const char *prof
[12] = { 0 }, *prof_names
[12] = {
2536 switch_event_header_t
*hi
;
2540 SWITCH_STANDARD_STREAM(stream
);
2543 stream
.write_function(&stream
, "%s&", prefix
);
2546 encode_buf
= malloc(encode_len
);
2547 switch_assert(encode_buf
);
2551 for (x
= 0; prof
[x
]; x
++) {
2552 if (zstr(prof
[x
])) {
2555 new_len
= (strlen(prof
[x
]) * 3) + 1;
2556 if (encode_len
< new_len
) {
2559 encode_len
= new_len
;
2561 if (!(tmp
= realloc(encode_buf
, encode_len
))) {
2567 switch_url_encode(prof
[x
], encode_buf
, encode_len
);
2568 stream
.write_function(&stream
, "%s=%s&", prof_names
[x
], encode_buf
);
2572 if ((hi
= event
->headers
)) {
2574 for (; hi
; hi
= hi
->next
) {
2575 char *var
= hi
->name
;
2576 char *val
= hi
->value
;
2578 if (vars_map
!= NULL
) {
2579 if ((data
= switch_core_hash_find(vars_map
, var
)) == NULL
|| strcasecmp(((char *) data
), "enabled"))
2584 new_len
= (strlen((char *) val
) * 3) + 1;
2585 if (encode_len
< new_len
) {
2588 encode_len
= new_len
;
2590 tmp
= realloc(encode_buf
, encode_len
);
2595 switch_url_encode((char *) val
, encode_buf
, encode_len
);
2596 stream
.write_function(&stream
, "%s=%s&", (char *) var
, encode_buf
);
2602 e
= (char *) stream
.data
+ (strlen((char *) stream
.data
) - 1);
2604 if (e
&& *e
== '&') {
2608 switch_safe_free(encode_buf
);
2613 SWITCH_DECLARE(int) switch_event_check_permission_list(switch_event_t
*list
, const char *name
)
2617 int default_allow
= 0;
2623 default_allow
= switch_test_flag(list
, EF_DEFAULT_ALLOW
);
2625 if (!list
->headers
) {
2626 return default_allow
;
2629 if ((v
= switch_event_get_header(list
, name
))) {
2642 SWITCH_DECLARE(void) switch_json_add_presence_data_cols(switch_event_t
*event
, cJSON
*json
, const char *prefix
)
2646 if (!prefix
) prefix
= "";
2648 if ((data
= switch_event_get_header(event
, "presence_data_cols"))) {
2649 char *cols
[128] = { 0 };
2650 char header_name
[128] = "";
2651 int col_count
= 0, i
= 0;
2652 char *data_copy
= NULL
;
2654 data_copy
= strdup(data
);
2656 col_count
= switch_split(data_copy
, ':', cols
);
2658 for (i
= 0; i
< col_count
; i
++) {
2659 const char *val
= NULL
;
2660 switch_snprintf(header_name
, sizeof(header_name
), "%s%s", prefix
, cols
[i
]);
2662 val
= switch_event_get_header(event
, cols
[i
]);
2663 json_add_child_string(json
, header_name
, val
);
2666 switch_safe_free(data_copy
);
2672 SWITCH_DECLARE(void) switch_event_add_presence_data_cols(switch_channel_t
*channel
, switch_event_t
*event
, const char *prefix
)
2676 if (!prefix
) prefix
= "";
2678 if ((data
= switch_channel_get_variable(channel
, "presence_data_cols"))) {
2679 char *cols
[128] = { 0 };
2680 char header_name
[128] = "";
2681 int col_count
= 0, i
= 0;
2682 char *data_copy
= NULL
;
2684 data_copy
= strdup(data
);
2686 col_count
= switch_split(data_copy
, ':', cols
);
2688 for (i
= 0; i
< col_count
; i
++) {
2689 const char *val
= NULL
;
2690 switch_snprintf(header_name
, sizeof(header_name
), "%s%s", prefix
, cols
[i
]);
2692 val
= switch_channel_get_variable(channel
, cols
[i
]);
2693 switch_event_add_header_string(event
, SWITCH_STACK_BOTTOM
, header_name
, val
);
2696 switch_safe_free(data_copy
);
2701 struct switch_event_channel_sub_node_head_s
;
2703 typedef struct switch_event_channel_sub_node_s
{
2704 switch_event_channel_func_t func
;
2705 switch_event_channel_id_t id
;
2706 struct switch_event_channel_sub_node_head_s
*head
;
2707 struct switch_event_channel_sub_node_s
*next
;
2708 } switch_event_channel_sub_node_t
;
2710 typedef struct switch_event_channel_sub_node_head_s
{
2711 switch_event_channel_sub_node_t
*node
;
2712 switch_event_channel_sub_node_t
*tail
;
2713 char *event_channel
;
2714 } switch_event_channel_sub_node_head_t
;
2716 static uint32_t switch_event_channel_unsub_head(switch_event_channel_func_t func
, switch_event_channel_sub_node_head_t
*head
)
2720 switch_event_channel_sub_node_t
*thisnp
= NULL
, *np
, *last
= NULL
;
2722 np
= head
->tail
= head
->node
;
2729 if (!func
|| thisnp
->func
== func
) {
2739 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG1
, "UNSUBBING %p [%s]\n", (void *)(intptr_t)thisnp
->func
, thisnp
->head
->event_channel
);
2742 thisnp
->func
= NULL
;
2753 static void unsub_all_switch_event_channel(void)
2755 switch_hash_index_t
*hi
= NULL
;
2758 switch_event_channel_sub_node_head_t
*head
;
2760 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
2762 while ((hi
= switch_core_hash_first_iter( event_channel_manager
.perm_hash
, hi
))) {
2763 switch_event_t
*vals
= NULL
;
2764 switch_core_hash_this(hi
, &var
, NULL
, &val
);
2765 vals
= (switch_event_t
*) val
;
2766 switch_core_hash_delete(event_channel_manager
.perm_hash
, var
);
2767 switch_event_destroy(&vals
);
2770 while ((hi
= switch_core_hash_first_iter( event_channel_manager
.hash
, hi
))) {
2771 switch_core_hash_this(hi
, NULL
, NULL
, &val
);
2772 head
= (switch_event_channel_sub_node_head_t
*) val
;
2773 switch_event_channel_unsub_head(NULL
, head
);
2774 switch_core_hash_delete(event_channel_manager
.hash
, head
->event_channel
);
2775 free(head
->event_channel
);
2779 switch_safe_free(hi
);
2780 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2783 static uint32_t switch_event_channel_unsub_channel(switch_event_channel_func_t func
, const char *event_channel
)
2785 switch_event_channel_sub_node_head_t
*head
;
2788 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
2790 if (!event_channel
) {
2791 switch_hash_index_t
*hi
;
2794 for (hi
= switch_core_hash_first(event_channel_manager
.hash
); hi
; hi
= switch_core_hash_next(&hi
)) {
2795 switch_core_hash_this(hi
, NULL
, NULL
, &val
);
2798 head
= (switch_event_channel_sub_node_head_t
*) val
;
2799 x
+= switch_event_channel_unsub_head(func
, head
);
2804 if ((head
= switch_core_hash_find(event_channel_manager
.hash
, event_channel
))) {
2805 x
+= switch_event_channel_unsub_head(func
, head
);
2809 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2814 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
)
2817 switch_event_channel_sub_node_t
*node
, *np
;
2818 switch_event_channel_sub_node_head_t
*head
;
2819 switch_status_t status
= SWITCH_STATUS_FALSE
;
2821 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
2823 if (!(head
= switch_core_hash_find(event_channel_manager
.hash
, event_channel
))) {
2824 switch_zmalloc(head
, sizeof(*head
));
2825 head
->event_channel
= strdup(event_channel
);
2826 switch_core_hash_insert(event_channel_manager
.hash
, event_channel
, head
);
2828 switch_zmalloc(node
, sizeof(*node
));
2835 status
= SWITCH_STATUS_SUCCESS
;
2839 for (np
= head
->node
; np
; np
= np
->next
) {
2840 if (np
->func
== func
) {
2847 switch_zmalloc(node
, sizeof(*node
));
2858 head
->tail
->next
= node
;
2859 head
->tail
= head
->tail
->next
;
2861 status
= SWITCH_STATUS_SUCCESS
;
2865 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2871 char *event_channel
;
2874 switch_event_channel_id_t id
;
2875 } event_channel_data_t
;
2879 static uint32_t _switch_event_channel_broadcast(const char *event_channel
, const char *broadcast_channel
,
2880 cJSON
*json
, const char *key
, switch_event_channel_id_t id
)
2882 switch_event_channel_sub_node_t
*np
;
2883 switch_event_channel_sub_node_head_t
*head
;
2886 switch_thread_rwlock_rdlock(event_channel_manager
.rwlock
);
2887 if ((head
= switch_core_hash_find(event_channel_manager
.hash
, event_channel
))) {
2888 for (np
= head
->node
; np
; np
= np
->next
) {
2893 np
->func(broadcast_channel
, json
, key
, id
);
2897 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
2902 static void destroy_ecd(event_channel_data_t
**ecdP
)
2904 event_channel_data_t
*ecd
= *ecdP
;
2907 switch_safe_free(ecd
->event_channel
);
2908 switch_safe_free(ecd
->key
);
2910 cJSON_Delete(ecd
->json
);
2917 static void ecd_deliver(event_channel_data_t
**ecdP
)
2919 event_channel_data_t
*ecd
= *ecdP
;
2924 _switch_event_channel_broadcast(ecd
->event_channel
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2926 if ((p
= strchr(ecd
->event_channel
, '.'))) {
2927 char *main_channel
= strdup(ecd
->event_channel
);
2928 p
= strchr(main_channel
, '.');
2930 _switch_event_channel_broadcast(main_channel
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2933 _switch_event_channel_broadcast(SWITCH_EVENT_CHANNEL_GLOBAL
, ecd
->event_channel
, ecd
->json
, ecd
->key
, ecd
->id
);
2938 static void *SWITCH_THREAD_FUNC
switch_event_channel_deliver_thread(switch_thread_t
*thread
, void *obj
)
2940 switch_queue_t
*queue
= (switch_queue_t
*) obj
;
2942 event_channel_data_t
*ecd
= NULL
;
2944 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
2946 EVENT_CHANNEL_DISPATCH_THREAD_COUNT
++;
2947 EVENT_CHANNEL_DISPATCH_THREAD_STARTING
= 0;
2948 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
2950 while(SYSTEM_RUNNING
) {
2952 if (switch_queue_pop(queue
, &pop
) != SWITCH_STATUS_SUCCESS
) {
2960 ecd
= (event_channel_data_t
*) pop
;
2965 while (switch_queue_trypop(queue
, &pop
) == SWITCH_STATUS_SUCCESS
) {
2966 ecd
= (event_channel_data_t
*) pop
;
2970 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
2972 EVENT_CHANNEL_DISPATCH_THREAD_COUNT
--;
2973 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
2975 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CONSOLE
, "Event Channel Dispatch Thread Ended.\n");
2979 SWITCH_DECLARE(switch_status_t
) switch_event_channel_broadcast(const char *event_channel
, cJSON
**json
, const char *key
, switch_event_channel_id_t id
)
2981 event_channel_data_t
*ecd
= NULL
;
2982 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
2985 if (!SYSTEM_RUNNING
) {
2986 cJSON_Delete(*json
);
2988 return SWITCH_STATUS_FALSE
;
2991 switch_zmalloc(ecd
, sizeof(*ecd
));
2993 ecd
->event_channel
= strdup(event_channel
);
2995 ecd
->key
= strdup(key
);
3000 switch_mutex_lock(EVENT_QUEUE_MUTEX
);
3001 if (!EVENT_CHANNEL_DISPATCH_THREAD_COUNT
&& !EVENT_CHANNEL_DISPATCH_THREAD_STARTING
&& SYSTEM_RUNNING
) {
3002 EVENT_CHANNEL_DISPATCH_THREAD_STARTING
= 1;
3005 switch_mutex_unlock(EVENT_QUEUE_MUTEX
);
3008 switch_thread_data_t
*td
;
3010 if (!EVENT_CHANNEL_DISPATCH_QUEUE
) {
3011 switch_queue_create(&EVENT_CHANNEL_DISPATCH_QUEUE
, DISPATCH_QUEUE_LEN
* MAX_DISPATCH
, THRUNTIME_POOL
);
3014 td
= malloc(sizeof(*td
));
3018 td
->func
= switch_event_channel_deliver_thread
;
3019 td
->obj
= EVENT_CHANNEL_DISPATCH_QUEUE
;
3022 switch_thread_pool_launch_thread(&td
);
3025 if ((status
= switch_queue_trypush(EVENT_CHANNEL_DISPATCH_QUEUE
, ecd
) != SWITCH_STATUS_SUCCESS
)) {
3026 cJSON_Delete(ecd
->json
);
3029 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "Event Channel Queue failure for channel %s\n", event_channel
);
3037 SWITCH_DECLARE(uint32_t) switch_event_channel_unbind(const char *event_channel
, switch_event_channel_func_t func
)
3039 return switch_event_channel_unsub_channel(func
, event_channel
);
3042 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
)
3045 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
3050 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
3051 *id
= event_channel_manager
.ID
++;
3052 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3055 status
= switch_event_channel_sub_channel(event_channel
, func
, *id
);
3060 SWITCH_DECLARE(switch_bool_t
) switch_event_channel_permission_verify(const char *cookie
, const char *event_channel
)
3062 switch_event_t
*vals
;
3063 switch_bool_t r
= SWITCH_FALSE
;
3065 switch_thread_rwlock_rdlock(event_channel_manager
.rwlock
);
3066 if ((vals
= switch_core_hash_find(event_channel_manager
.perm_hash
, cookie
))) {
3067 r
= switch_true(switch_event_get_header(vals
, event_channel
));
3069 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3074 SWITCH_DECLARE(void) switch_event_channel_permission_modify(const char *cookie
, const char *event_channel
, switch_bool_t set
)
3076 switch_event_t
*vals
;
3078 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
3079 if (!(vals
= switch_core_hash_find(event_channel_manager
.perm_hash
, cookie
))) {
3082 switch_event_create_plain(&vals
, SWITCH_EVENT_CHANNEL_DATA
);
3083 switch_core_hash_insert(event_channel_manager
.perm_hash
, cookie
, vals
);
3087 switch_event_add_header_string(vals
, SWITCH_STACK_BOTTOM
, event_channel
, "true");
3089 switch_event_del_header(vals
, event_channel
);
3095 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3098 SWITCH_DECLARE(void) switch_event_channel_permission_clear(const char *cookie
)
3100 switch_event_t
*vals
;
3102 switch_thread_rwlock_wrlock(event_channel_manager
.rwlock
);
3103 if ((vals
= switch_core_hash_find(event_channel_manager
.perm_hash
, cookie
))) {
3104 switch_core_hash_delete(event_channel_manager
.perm_hash
, cookie
);
3105 switch_event_destroy(&vals
);
3107 switch_thread_rwlock_unlock(event_channel_manager
.rwlock
);
3111 typedef struct alias_node_s
{
3112 char *event_channel
;
3115 struct alias_node_s
*next
;
3118 typedef struct la_node_s
{
3121 struct la_node_s
*next
;
3125 struct switch_live_array_s
{
3126 char *event_channel
;
3131 switch_memory_pool_t
*pool
;
3132 switch_hash_t
*hash
;
3133 switch_mutex_t
*mutex
;
3136 switch_bool_t visible
;
3138 switch_event_channel_id_t channel_id
;
3139 switch_live_array_command_handler_t command_handler
;
3141 alias_node_t
*aliases
;
3145 static switch_status_t
la_broadcast(switch_live_array_t
*la
, cJSON
**json
)
3150 switch_mutex_lock(la
->mutex
);
3151 for (np
= la
->aliases
; np
; np
= np
->next
) {
3152 cJSON
*dup
= cJSON_Duplicate(*json
, 1);
3153 cJSON
*data
= cJSON_GetObjectItem(dup
, "data");
3155 cJSON_ReplaceItemInObject(dup
, "eventChannel", cJSON_CreateString(np
->event_channel
));
3156 cJSON_ReplaceItemInObject(data
, "name", cJSON_CreateString(np
->name
));
3158 switch_event_channel_broadcast(np
->event_channel
, &dup
, __FILE__
, la
->channel_id
);
3160 switch_mutex_unlock(la
->mutex
);
3163 return switch_event_channel_broadcast(la
->event_channel
, json
, __FILE__
, la
->channel_id
);
3168 SWITCH_DECLARE(switch_status_t
) switch_live_array_visible(switch_live_array_t
*la
, switch_bool_t visible
, switch_bool_t force
)
3170 switch_status_t status
= SWITCH_STATUS_FALSE
;
3172 switch_mutex_lock(la
->mutex
);
3173 if (la
->visible
!= visible
|| force
) {
3176 msg
= cJSON_CreateObject();
3177 data
= json_add_child_obj(msg
, "data", NULL
);
3179 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3180 cJSON_AddItemToObject(data
, "action", cJSON_CreateString(visible
? "hide" : "show"));
3181 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3183 la_broadcast(la
, &msg
);
3185 la
->visible
= visible
;
3187 switch_mutex_unlock(la
->mutex
);
3192 SWITCH_DECLARE(switch_status_t
) switch_live_array_clear(switch_live_array_t
*la
)
3194 la_node_t
*cur
, *np
;
3197 switch_mutex_lock(la
->mutex
);
3200 msg
= cJSON_CreateObject();
3201 data
= json_add_child_obj(msg
, "data", NULL
);
3203 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3204 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("clear"));
3205 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3206 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(-1));
3207 cJSON_AddItemToObject(data
, "data", cJSON_CreateObject());
3209 la_broadcast(la
, &msg
);
3214 cJSON_Delete(cur
->obj
);
3219 la
->head
= la
->tail
= NULL
;
3221 switch_mutex_unlock(la
->mutex
);
3223 return SWITCH_STATUS_SUCCESS
;
3226 SWITCH_DECLARE(switch_status_t
) switch_live_array_bootstrap(switch_live_array_t
*la
, const char *sessid
, switch_event_channel_id_t channel_id
)
3231 switch_mutex_lock(la
->mutex
);
3234 msg
= cJSON_CreateObject();
3235 data
= json_add_child_obj(msg
, "data", NULL
);
3237 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3238 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("clear"));
3239 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3240 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(-1));
3241 cJSON_AddItemToObject(data
, "data", cJSON_CreateObject());
3243 switch_event_channel_broadcast(la
->event_channel
, &msg
, __FILE__
, channel_id
);
3245 for (np
= la
->head
; np
; np
= np
->next
) {
3246 msg
= cJSON_CreateObject();
3247 data
= json_add_child_obj(msg
, "data", NULL
);
3249 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3250 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("add"));
3251 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3252 cJSON_AddItemToObject(data
, "hashKey", cJSON_CreateString(np
->name
));
3253 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3254 cJSON_AddItemToObject(data
, "data", cJSON_Duplicate(np
->obj
, 1));
3256 cJSON_AddItemToObject(msg
, "sessid", cJSON_CreateString(sessid
));
3258 switch_event_channel_broadcast(la
->event_channel
, &msg
, __FILE__
, channel_id
);
3263 msg
= cJSON_CreateObject();
3264 data
= json_add_child_obj(msg
, "data", NULL
);
3266 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3267 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("bootObj"));
3268 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3269 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(-1));
3272 cJSON_AddItemToObject(msg
, "sessid", cJSON_CreateString(sessid
));
3275 data
= json_add_child_array(data
, "data");
3277 for (np
= la
->head
; np
; np
= np
->next
) {
3278 cJSON
*row
= cJSON_CreateArray();
3279 cJSON_AddItemToArray(row
, cJSON_CreateString(np
->name
));
3280 cJSON_AddItemToArray(row
, cJSON_Duplicate(np
->obj
, 1));
3281 cJSON_AddItemToArray(data
, row
);
3284 switch_event_channel_broadcast(la
->event_channel
, &msg
, __FILE__
, channel_id
);
3290 switch_live_array_visible(la
, SWITCH_FALSE
, SWITCH_TRUE
);
3293 switch_mutex_unlock(la
->mutex
);
3295 return SWITCH_STATUS_SUCCESS
;
3298 SWITCH_DECLARE(switch_status_t
) switch_live_array_destroy(switch_live_array_t
**live_arrayP
)
3300 switch_live_array_t
*la
= *live_arrayP
;
3301 switch_memory_pool_t
*pool
;
3305 *live_arrayP
= NULL
;
3307 switch_mutex_lock(la
->mutex
);
3311 if (la
->refs
) done
= 1;
3312 switch_mutex_unlock(la
->mutex
);
3315 return SWITCH_STATUS_SUCCESS
;
3320 switch_live_array_clear(la
);
3322 switch_core_hash_destroy(&la
->hash
);
3324 switch_mutex_lock(event_channel_manager
.lamutex
);
3325 switch_core_hash_delete(event_channel_manager
.lahash
, la
->key
);
3326 for (np
= la
->aliases
; np
; np
= np
->next
) {
3327 switch_core_hash_delete(event_channel_manager
.lahash
, np
->key
);
3329 switch_mutex_unlock(event_channel_manager
.lamutex
);
3331 switch_core_destroy_memory_pool(&pool
);
3333 return SWITCH_STATUS_SUCCESS
;
3336 SWITCH_DECLARE(switch_bool_t
) switch_live_array_isnew(switch_live_array_t
*la
)
3341 SWITCH_DECLARE(switch_bool_t
) switch_live_array_clear_alias(switch_live_array_t
*la
, const char *event_channel
, const char *name
)
3343 alias_node_t
*np
, *last
= NULL
, *del
= NULL
;
3344 switch_bool_t r
= SWITCH_FALSE
;
3346 switch_mutex_lock(la
->mutex
);
3347 for (np
= la
->aliases
; np
; np
= np
->next
) {
3348 if (!strcmp(np
->event_channel
, event_channel
) && !strcmp(np
->name
, name
)) {
3353 last
->next
= np
->next
;
3355 la
->aliases
= np
->next
;
3361 switch_mutex_unlock(la
->mutex
);
3364 switch_mutex_lock(event_channel_manager
.lamutex
);
3365 switch_core_hash_delete(event_channel_manager
.lahash
, del
->key
);
3366 switch_mutex_unlock(event_channel_manager
.lamutex
);
3373 SWITCH_DECLARE(switch_bool_t
) switch_live_array_add_alias(switch_live_array_t
*la
, const char *event_channel
, const char *name
)
3375 alias_node_t
*node
= 0, *np
;
3376 switch_bool_t exist
= SWITCH_FALSE
;
3378 switch_mutex_lock(la
->mutex
);
3379 for (np
= la
->aliases
; np
&& np
->next
; np
= np
->next
) {
3380 if (!strcmp(np
->event_channel
, event_channel
) && !strcmp(np
->name
, name
)) {
3381 exist
= SWITCH_TRUE
;
3387 node
= switch_core_alloc(la
->pool
, sizeof(*node
));
3388 node
->event_channel
= switch_core_strdup(la
->pool
, event_channel
);
3389 node
->name
= switch_core_strdup(la
->pool
, name
);
3390 node
->key
= switch_core_sprintf(la
->pool
, "%s.%s", event_channel
, name
);
3399 switch_mutex_unlock(la
->mutex
);
3402 switch_mutex_lock(event_channel_manager
.lamutex
);
3403 switch_core_hash_insert(event_channel_manager
.lahash
, node
->key
, la
);
3404 switch_mutex_unlock(event_channel_manager
.lamutex
);
3411 SWITCH_DECLARE(switch_status_t
) switch_live_array_create(const char *event_channel
, const char *name
,
3412 switch_event_channel_id_t channel_id
, switch_live_array_t
**live_arrayP
)
3414 switch_live_array_t
*la
= NULL
;
3415 switch_memory_pool_t
*pool
;
3418 switch_core_new_memory_pool(&pool
);
3419 key
= switch_core_sprintf(pool
, "%s.%s", event_channel
, name
);
3421 switch_mutex_lock(event_channel_manager
.lamutex
);
3422 la
= switch_core_hash_find(event_channel_manager
.lahash
, key
);
3423 switch_mutex_unlock(event_channel_manager
.lamutex
);
3426 la
->new = SWITCH_FALSE
;
3428 la
= switch_core_alloc(pool
, sizeof(*la
));
3431 la
->visible
= SWITCH_TRUE
;
3432 la
->event_channel
= switch_core_strdup(la
->pool
, event_channel
);
3433 la
->name
= switch_core_strdup(la
->pool
, name
);
3435 la
->new = SWITCH_TRUE
;
3436 la
->channel_id
= channel_id
;
3437 switch_core_hash_init(&la
->hash
);
3438 switch_mutex_init(&la
->mutex
, SWITCH_MUTEX_NESTED
, la
->pool
);
3440 switch_mutex_lock(event_channel_manager
.lamutex
);
3441 switch_core_hash_insert(event_channel_manager
.lahash
, la
->key
, la
);
3442 switch_mutex_unlock(event_channel_manager
.lamutex
);
3445 switch_mutex_lock(la
->mutex
);
3447 switch_mutex_unlock(la
->mutex
);
3451 return SWITCH_STATUS_SUCCESS
;
3454 SWITCH_DECLARE(cJSON
*) switch_live_array_get(switch_live_array_t
*la
, const char *name
)
3459 switch_mutex_lock(la
->mutex
);
3460 if ((node
= switch_core_hash_find(la
->hash
, name
))) {
3461 dup
= cJSON_Duplicate(node
->obj
, 1);
3463 switch_mutex_unlock(la
->mutex
);
3468 SWITCH_DECLARE(cJSON
*) switch_live_array_get_idx(switch_live_array_t
*la
, int idx
)
3473 switch_mutex_lock(la
->mutex
);
3474 for (node
= la
->head
; node
; node
= node
->next
) {
3475 if (node
->pos
== idx
) {
3476 dup
= cJSON_Duplicate(node
->obj
, 1);
3480 switch_mutex_unlock(la
->mutex
);
3485 SWITCH_DECLARE(void) switch_live_array_lock(switch_live_array_t
*la
)
3487 switch_mutex_lock(la
->mutex
);
3490 SWITCH_DECLARE(void) switch_live_array_unlock(switch_live_array_t
*la
)
3492 switch_mutex_unlock(la
->mutex
);
3495 SWITCH_DECLARE(switch_status_t
) switch_live_array_del(switch_live_array_t
*la
, const char *name
)
3497 switch_status_t status
= SWITCH_STATUS_FALSE
;
3498 la_node_t
*node
, *cur
, *np
, *last
= NULL
;
3499 cJSON
*msg
, *data
= NULL
;
3501 switch_mutex_lock(la
->mutex
);
3502 if ((node
= switch_core_hash_find(la
->hash
, name
))) {
3511 last
->next
= cur
->next
;
3513 la
->head
= cur
->next
;
3515 switch_core_hash_delete(la
->hash
, name
);
3517 msg
= cJSON_CreateObject();
3518 data
= json_add_child_obj(msg
, "data", NULL
);
3520 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3521 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3522 cJSON_AddItemToObject(data
, "action", cJSON_CreateString("del"));
3523 cJSON_AddItemToObject(data
, "hashKey", cJSON_CreateString(cur
->name
));
3524 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3525 cJSON_AddItemToObject(data
, "data", cur
->obj
);
3528 la_broadcast(la
, &msg
);
3532 cur
->pos
= la
->pos
++;
3538 switch_mutex_unlock(la
->mutex
);
3543 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
)
3546 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
3547 const char *action
= "add";
3548 cJSON
*msg
= NULL
, *data
= NULL
;
3550 switch_mutex_lock(la
->mutex
);
3552 if ((node
= switch_core_hash_find(la
->hash
, name
))) {
3558 cJSON_Delete(node
->obj
);
3563 switch_zmalloc(node
, sizeof(*node
));
3565 node
->name
= strdup(name
);
3566 switch_core_hash_insert(la
->hash
, name
, node
);
3568 if (index
> -1 && index
< la
->pos
&& la
->head
) {
3569 la_node_t
*np
, *last
= NULL
;
3572 for(np
= la
->head
; np
; np
= np
->next
) {
3576 node
->next
= last
->next
;
3580 node
->next
= la
->head
;
3595 node
->pos
= la
->pos
++;
3601 la
->tail
->next
= node
;
3609 node
->obj
= cJSON_Duplicate(*obj
, 1);
3614 msg
= cJSON_CreateObject();
3615 data
= json_add_child_obj(msg
, "data", NULL
);
3617 cJSON_AddItemToObject(msg
, "eventChannel", cJSON_CreateString(la
->event_channel
));
3618 cJSON_AddItemToObject(data
, "action", cJSON_CreateString(action
));
3621 cJSON_AddItemToObject(data
, "arrIndex", cJSON_CreateNumber(index
));
3624 cJSON_AddItemToObject(data
, "name", cJSON_CreateString(la
->name
));
3625 cJSON_AddItemToObject(data
, "hashKey", cJSON_CreateString(node
->name
));
3626 cJSON_AddItemToObject(data
, "wireSerno", cJSON_CreateNumber(la
->serno
++));
3627 cJSON_AddItemToObject(data
, "data", cJSON_Duplicate(node
->obj
, 1));
3629 la_broadcast(la
, &msg
);
3631 switch_mutex_unlock(la
->mutex
);
3636 SWITCH_DECLARE(void) switch_live_array_set_user_data(switch_live_array_t
*la
, void *user_data
)
3639 la
->user_data
= user_data
;
3642 SWITCH_DECLARE(void) switch_live_array_set_command_handler(switch_live_array_t
*la
, switch_live_array_command_handler_t command_handler
)
3645 la
->command_handler
= command_handler
;
3649 SWITCH_DECLARE(void) switch_live_array_parse_json(cJSON
*json
, switch_event_channel_id_t channel_id
)
3651 const char *context
= NULL
, *name
= NULL
;
3652 switch_live_array_t
*la
= NULL
;
3655 if ((jla
= cJSON_GetObjectItem(json
, "data")) && (jla
= cJSON_GetObjectItem(jla
, "liveArray"))) {
3657 if ((context
= cJSON_GetObjectCstr(jla
, "context")) && (name
= cJSON_GetObjectCstr(jla
, "name"))) {
3658 const char *command
= cJSON_GetObjectCstr(jla
, "command");
3659 const char *sessid
= cJSON_GetObjectCstr(json
, "sessid");
3662 if (switch_live_array_create(context
, name
, channel_id
, &la
) == SWITCH_STATUS_SUCCESS
) {
3664 if (!strcasecmp(command
, "bootstrap")) {
3665 switch_live_array_bootstrap(la
, sessid
, channel_id
);
3667 if (la
->command_handler
) {
3668 la
->command_handler(la
, command
, sessid
, jla
, la
->user_data
);
3671 switch_live_array_destroy(&la
);
3682 * indent-tabs-mode:t
3687 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: