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 * Juan Jose Comellas <juanjo@comellas.org>
28 * Seven Du <dujinfang@gmail.com>
29 * Windy Wang <xiaofengcanyuexp@163.com>
31 * switch_utils.c -- Compatibility and Helper Code
36 #include "private/switch_apr_pvt.h"
38 #include <arpa/inet.h>
39 #if defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_RESOURCE_H)
41 #include <sys/resource.h>
43 #include <sys/types.h>
46 #include <intsafe.h> /* SIZETMult() */
47 /* process.h is required for _getpid() */
50 #include "private/switch_core_pvt.h"
51 #define ESCAPE_META '\\'
52 #ifdef SWITCH_HAVE_GUMBO
56 #if defined(HAVE_OPENSSL)
57 #include <openssl/evp.h>
61 #include <malloc.h> /* mallinfo() */
64 struct switch_network_node
{
72 switch_network_port_range_t port_range
;
73 struct switch_network_node
*next
;
75 typedef struct switch_network_node switch_network_node_t
;
77 struct switch_network_list
{
78 struct switch_network_node
*node_head
;
79 switch_bool_t default_type
;
80 switch_memory_pool_t
*pool
;
84 SWITCH_DECLARE(void *) switch_calloc(size_t nmemb
, size_t size
)
86 return calloc(nmemb
, size
);
90 SWITCH_DECLARE(int) switch_inet_pton(int af
, const char *src
, void *dst
)
92 return inet_pton(af
, src
, dst
);
96 SWITCH_DECLARE(char *) switch_print_host(switch_sockaddr_t
*addr
, char *buf
, switch_size_t len
)
100 switch_get_addr(buf
, len
, addr
);
101 port
= switch_sockaddr_get_port(addr
);
103 snprintf(buf
+ strlen(buf
), len
- strlen(buf
), ":%d", port
);
107 SWITCH_DECLARE(switch_status_t
) switch_frame_alloc(switch_frame_t
**frame
, switch_size_t size
)
109 switch_frame_t
*new_frame
;
111 switch_zmalloc(new_frame
, sizeof(*new_frame
));
113 switch_set_flag(new_frame
, SFF_DYNAMIC
);
114 new_frame
->buflen
= (uint32_t)size
;
115 new_frame
->data
= malloc(size
);
116 switch_assert(new_frame
->data
);
120 return SWITCH_STATUS_SUCCESS
;
124 typedef struct switch_frame_node_s
{
125 switch_frame_t
*frame
;
127 struct switch_frame_node_s
*prev
;
128 struct switch_frame_node_s
*next
;
129 } switch_frame_node_t
;
131 struct switch_frame_buffer_s
{
132 switch_frame_node_t
*head
;
133 switch_memory_pool_t
*pool
;
134 switch_queue_t
*queue
;
135 switch_mutex_t
*mutex
;
139 static switch_frame_t
*find_free_frame(switch_frame_buffer_t
*fb
, switch_frame_t
*orig
)
141 switch_frame_node_t
*np
;
143 switch_mutex_lock(fb
->mutex
);
145 for (np
= fb
->head
; np
; np
= np
->next
) {
146 if (!np
->inuse
&& ((orig
->packet
&& np
->frame
->packet
) || (!orig
->packet
&& !np
->frame
->packet
))) {
148 if (np
== fb
->head
) {
150 } else if (np
->prev
) {
151 np
->prev
->next
= np
->next
;
155 np
->next
->prev
= np
->prev
;
159 np
->prev
= np
->next
= NULL
;
165 np
= switch_core_alloc(fb
->pool
, sizeof(*np
));
166 np
->frame
= switch_core_alloc(fb
->pool
, sizeof(*np
->frame
));
169 np
->frame
->packet
= switch_core_alloc(fb
->pool
, SWITCH_RTP_MAX_BUF_LEN
);
171 np
->frame
->packet
= NULL
;
172 np
->frame
->data
= switch_core_alloc(fb
->pool
, SWITCH_RTP_MAX_BUF_LEN
);
173 np
->frame
->buflen
= SWITCH_RTP_MAX_BUF_LEN
;
177 np
->frame
->samples
= orig
->samples
;
178 np
->frame
->rate
= orig
->rate
;
179 np
->frame
->channels
= orig
->channels
;
180 np
->frame
->payload
= orig
->payload
;
181 np
->frame
->timestamp
= orig
->timestamp
;
182 np
->frame
->seq
= orig
->seq
;
183 np
->frame
->ssrc
= orig
->ssrc
;
184 np
->frame
->m
= orig
->m
;
185 np
->frame
->flags
= orig
->flags
;
186 np
->frame
->codec
= orig
->codec
;
187 np
->frame
->pmap
= orig
->pmap
;
188 np
->frame
->img
= NULL
;
189 np
->frame
->extra_data
= np
;
192 switch_set_flag(np
->frame
, SFF_DYNAMIC
);
195 memcpy(np
->frame
->packet
, orig
->packet
, orig
->packetlen
);
196 np
->frame
->packetlen
= orig
->packetlen
;
197 np
->frame
->data
= ((unsigned char *)np
->frame
->packet
) + 12;
198 np
->frame
->datalen
= orig
->datalen
;
200 np
->frame
->packet
= NULL
;
201 np
->frame
->packetlen
= 0;
202 memcpy(np
->frame
->data
, orig
->data
, orig
->datalen
);
203 np
->frame
->datalen
= orig
->datalen
;
206 if (orig
->img
&& !switch_test_flag(orig
, SFF_ENCODED
)) {
207 switch_img_copy(orig
->img
, &np
->frame
->img
);
210 switch_mutex_unlock(fb
->mutex
);
215 SWITCH_DECLARE(switch_status_t
) switch_frame_buffer_free(switch_frame_buffer_t
*fb
, switch_frame_t
**frameP
)
217 switch_frame_t
*old_frame
;
218 switch_frame_node_t
*node
;
220 switch_mutex_lock(fb
->mutex
);
225 node
= (switch_frame_node_t
*) old_frame
->extra_data
;
227 switch_img_free(&node
->frame
->img
);
232 fb
->head
->prev
= node
;
235 node
->next
= fb
->head
;
239 switch_assert(node
->next
!= node
);
240 switch_assert(node
->prev
!= node
);
243 switch_mutex_unlock(fb
->mutex
);
245 return SWITCH_STATUS_SUCCESS
;
248 SWITCH_DECLARE(switch_status_t
) switch_frame_buffer_dup(switch_frame_buffer_t
*fb
, switch_frame_t
*orig
, switch_frame_t
**clone
)
250 switch_frame_t
*new_frame
;
253 return SWITCH_STATUS_FALSE
;
256 switch_assert(orig
->buflen
);
258 new_frame
= find_free_frame(fb
, orig
);
262 return SWITCH_STATUS_SUCCESS
;
265 SWITCH_DECLARE(switch_status_t
) switch_frame_buffer_push(switch_frame_buffer_t
*fb
, void *ptr
)
267 return switch_queue_push(fb
->queue
, ptr
);
270 SWITCH_DECLARE(switch_status_t
) switch_frame_buffer_trypush(switch_frame_buffer_t
*fb
, void *ptr
)
272 return switch_queue_trypush(fb
->queue
, ptr
);
275 SWITCH_DECLARE(switch_status_t
) switch_frame_buffer_pop(switch_frame_buffer_t
*fb
, void **ptr
)
277 return switch_queue_pop(fb
->queue
, ptr
);
280 SWITCH_DECLARE(switch_status_t
) switch_frame_buffer_trypop(switch_frame_buffer_t
*fb
, void **ptr
)
282 return switch_queue_trypop(fb
->queue
, ptr
);
285 SWITCH_DECLARE(int) switch_frame_buffer_size(switch_frame_buffer_t
*fb
)
287 return switch_queue_size(fb
->queue
);
290 SWITCH_DECLARE(switch_status_t
) switch_frame_buffer_destroy(switch_frame_buffer_t
**fbP
)
292 switch_frame_buffer_t
*fb
= *fbP
;
293 switch_memory_pool_t
*pool
;
296 switch_core_destroy_memory_pool(&pool
);
298 return SWITCH_STATUS_SUCCESS
;
301 SWITCH_DECLARE(switch_status_t
) switch_frame_buffer_create(switch_frame_buffer_t
**fbP
, switch_size_t qlen
)
303 switch_frame_buffer_t
*fb
;
304 switch_memory_pool_t
*pool
;
306 if (!qlen
) qlen
= 500;
308 switch_core_new_memory_pool(&pool
);
309 fb
= switch_core_alloc(pool
, sizeof(*fb
));
311 switch_queue_create(&fb
->queue
, qlen
, fb
->pool
);
312 switch_mutex_init(&fb
->mutex
, SWITCH_MUTEX_NESTED
, pool
);
315 return SWITCH_STATUS_SUCCESS
;
319 SWITCH_DECLARE(switch_status_t
) switch_frame_dup(switch_frame_t
*orig
, switch_frame_t
**clone
)
321 switch_frame_t
*new_frame
;
324 return SWITCH_STATUS_FALSE
;
327 switch_assert(orig
->buflen
);
329 new_frame
= malloc(sizeof(*new_frame
));
330 switch_assert(new_frame
);
333 switch_set_flag(new_frame
, SFF_DYNAMIC
);
336 new_frame
->packet
= malloc(SWITCH_RTP_MAX_BUF_LEN
);
337 switch_assert(new_frame
->packet
);
338 memcpy(new_frame
->packet
, orig
->packet
, orig
->packetlen
);
339 new_frame
->data
= ((unsigned char *)new_frame
->packet
) + 12;
341 new_frame
->packet
= NULL
;
342 new_frame
->data
= malloc(new_frame
->buflen
);
343 switch_assert(new_frame
->data
);
344 memcpy(new_frame
->data
, orig
->data
, orig
->datalen
);
348 new_frame
->codec
= orig
->codec
;
349 new_frame
->pmap
= orig
->pmap
;
350 new_frame
->img
= NULL
;
353 if (orig
->img
&& !switch_test_flag(orig
, SFF_ENCODED
)) {
354 switch_img_copy(orig
->img
, &new_frame
->img
);
358 return SWITCH_STATUS_SUCCESS
;
361 SWITCH_DECLARE(switch_status_t
) switch_frame_free(switch_frame_t
**frame
)
366 return SWITCH_STATUS_FALSE
;
371 if (!f
|| !switch_test_flag(f
, SFF_DYNAMIC
)) {
372 return SWITCH_STATUS_FALSE
;
378 switch_img_free(&(f
->img
));
382 switch_safe_free(f
->packet
);
384 switch_safe_free(f
->data
);
389 return SWITCH_STATUS_SUCCESS
;
392 SWITCH_DECLARE(int) switch_strcasecmp_any(const char *str
, ...)
395 const char *next_str
= 0;
400 while ((next_str
= va_arg(ap
, const char *))) {
401 if (!strcasecmp(str
, next_str
)) {
413 SWITCH_DECLARE(char *) switch_find_parameter(const char *str
, const char *param
, switch_memory_pool_t
*pool
)
415 char *e
, *r
= NULL
, *ptr
= NULL
, *next
= NULL
;
423 next
= strchr(ptr
, ';');
425 if (!strncasecmp(ptr
, param
, len
) && *e
== '=') {
433 e
= ptr
+ strlen(ptr
);
436 mlen
= (e
- ptr
) + 1;
439 r
= switch_core_alloc(pool
, mlen
);
444 switch_snprintf(r
, mlen
, "%s", ptr
);
457 SWITCH_DECLARE(switch_status_t
) switch_network_list_create(switch_network_list_t
**list
, const char *name
, switch_bool_t default_type
,
458 switch_memory_pool_t
*pool
)
460 switch_network_list_t
*new_list
;
463 switch_core_new_memory_pool(&pool
);
466 new_list
= switch_core_alloc(pool
, sizeof(**list
));
467 new_list
->pool
= pool
;
468 new_list
->default_type
= default_type
;
469 new_list
->name
= switch_core_strdup(new_list
->pool
, name
);
473 return SWITCH_STATUS_SUCCESS
;
476 #define IN6_AND_MASK(result, ip, mask) \
477 ((uint32_t *) (result))[0] =((const uint32_t *) (ip))[0] & ((const uint32_t *)(mask))[0]; \
478 ((uint32_t *) (result))[1] =((const uint32_t *) (ip))[1] & ((const uint32_t *)(mask))[1]; \
479 ((uint32_t *) (result))[2] =((const uint32_t *) (ip))[2] & ((const uint32_t *)(mask))[2]; \
480 ((uint32_t *) (result))[3] =((const uint32_t *) (ip))[3] & ((const uint32_t *)(mask))[3];
481 SWITCH_DECLARE(switch_bool_t
) switch_testv6_subnet(ip_t _ip
, ip_t _net
, ip_t _mask
) {
482 if (!IN6_IS_ADDR_UNSPECIFIED(&_mask
.v6
)) {
483 struct in6_addr a
, b
;
484 IN6_AND_MASK(&a
, &_net
, &_mask
);
485 IN6_AND_MASK(&b
, &_ip
, &_mask
);
486 return !memcmp(&a
,&b
, sizeof(struct in6_addr
));
488 if (!IN6_IS_ADDR_UNSPECIFIED(&_net
.v6
)) {
489 return !memcmp(&_net
,&_ip
,sizeof(struct in6_addr
));
491 else return SWITCH_TRUE
;
495 SWITCH_DECLARE(switch_bool_t
) switch_network_list_validate_ip6_port_token(switch_network_list_t
*list
, ip_t ip
, int port
, const char **token
)
497 switch_network_node_t
*node
;
498 switch_bool_t ok
= list
->default_type
;
501 for (node
= list
->node_head
; node
; node
= node
->next
) {
502 if (node
->family
== AF_INET
) continue;
504 if (node
->bits
>= bits
&& switch_testv6_subnet(ip
, node
->ip
, node
->mask
)) {
514 *token
= node
->token
;
522 SWITCH_DECLARE(switch_bool_t
) is_port_in_node(int port
, switch_network_node_t
*node
)
526 if(node
->port_range
.port
!= 0 && node
->port_range
.port
!= port
)
528 if(node
->port_range
.ports
[0] != 0) {
530 for(i
=0; i
< MAX_NETWORK_PORTS
&& node
->port_range
.ports
[i
] != 0; i
++) {
531 if(port
== node
->port_range
.ports
[i
])
536 if(node
->port_range
.min_port
!= 0 || node
->port_range
.max_port
!= 0) {
537 if(port
>= node
->port_range
.min_port
&& port
<= node
->port_range
.max_port
)
544 SWITCH_DECLARE(switch_bool_t
) switch_network_list_validate_ip_port_token(switch_network_list_t
*list
, uint32_t ip
, int port
, const char **token
)
546 switch_network_node_t
*node
;
547 switch_bool_t ok
= list
->default_type
;
550 for (node
= list
->node_head
; node
; node
= node
->next
) {
551 if (node
->family
== AF_INET6
) continue; /* want AF_INET */
552 if (node
->bits
>= bits
&& switch_test_subnet(ip
, node
->ip
.v4
, node
->mask
.v4
) && is_port_in_node(port
, node
)) {
562 *token
= node
->token
;
570 SWITCH_DECLARE(switch_bool_t
) switch_network_list_validate_ip6_token(switch_network_list_t
*list
, ip_t ip
, const char **token
)
572 return switch_network_list_validate_ip6_port_token(list
, ip
, 0, token
);
575 SWITCH_DECLARE(switch_bool_t
) switch_network_list_validate_ip_token(switch_network_list_t
*list
, uint32_t ip
, const char **token
)
577 return switch_network_list_validate_ip_port_token(list
, ip
, 0, token
);
580 SWITCH_DECLARE(char *) switch_network_ipv4_mapped_ipv6_addr(const char* ip_str
)
582 /* ipv4 mapped ipv6 address */
584 if (strncasecmp(ip_str
, "::ffff:", 7)) {
588 return strdup(ip_str
+ 7);
591 SWITCH_DECLARE(char*) switch_network_port_range_to_string(switch_network_port_range_p port
)
597 if (port
->port
!= 0) {
598 return switch_mprintf("port: %i ", port
->port
);
601 if (port
->ports
[0] != 0) {
603 char buf
[MAX_NETWORK_PORTS
* 6];
604 for (i
= 0; i
< MAX_NETWORK_PORTS
&& port
->ports
[i
] != 0; i
++) {
605 written
+= snprintf(buf
+ written
, sizeof(buf
) - written
, (i
!= 0 ? ", %u" : "%u"), port
->ports
[i
]);
607 return switch_mprintf("ports: [%s] ", buf
);
610 if (port
->min_port
!= 0 || port
->max_port
!= 0) {
611 return switch_mprintf("port range: [%i-%i] ", port
->min_port
, port
->max_port
);
617 SWITCH_DECLARE(switch_status_t
) switch_network_list_perform_add_cidr_token(switch_network_list_t
*list
, const char *cidr_str
, switch_bool_t ok
,
618 const char *token
, switch_network_port_range_p port
)
622 switch_network_node_t
*node
;
626 if ((ipv4
= switch_network_ipv4_mapped_ipv6_addr(cidr_str
))) {
630 ports
= switch_network_port_range_to_string(port
);
632 if (switch_parse_cidr(cidr_str
, &ip
, &mask
, &bits
)) {
633 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Error Adding %s %s(%s) [%s] to list %s\n",
634 cidr_str
, ports
? ports
: "", ok
? "allow" : "deny", switch_str_nil(token
), list
->name
);
635 switch_safe_free(ipv4
);
636 switch_safe_free(ports
);
637 return SWITCH_STATUS_GENERR
;
640 node
= switch_core_alloc(list
->pool
, sizeof(*node
));
646 node
->str
= switch_core_strdup(list
->pool
, cidr_str
);
648 memcpy(&node
->port_range
, port
, sizeof(switch_network_port_range_t
));
652 if (strchr(cidr_str
,':')) {
653 node
->family
= AF_INET6
;
655 node
->family
= AF_INET
;
659 node
->token
= switch_core_strdup(list
->pool
, token
);
662 node
->next
= list
->node_head
;
663 list
->node_head
= node
;
665 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_NOTICE
, "Adding %s %s(%s) [%s] to list %s\n",
666 cidr_str
, ports
? ports
: "", ok
? "allow" : "deny", switch_str_nil(token
), list
->name
);
668 switch_safe_free(ipv4
);
669 switch_safe_free(ports
);
670 return SWITCH_STATUS_SUCCESS
;
673 SWITCH_DECLARE(switch_status_t
) switch_network_list_add_cidr_port_token(switch_network_list_t
*list
, const char *cidr_str
, switch_bool_t ok
, const char *token
, switch_network_port_range_p port
)
675 char *cidr_str_dup
= NULL
;
676 switch_status_t status
= SWITCH_STATUS_SUCCESS
;
678 if (strchr(cidr_str
, ',')) {
679 char *argv
[32] = { 0 };
681 cidr_str_dup
= strdup(cidr_str
);
683 switch_assert(cidr_str_dup
);
684 if ((argc
= switch_separate_string(cidr_str_dup
, ',', argv
, (sizeof(argv
) / sizeof(argv
[0]))))) {
685 for (i
= 0; i
< argc
; i
++) {
686 switch_status_t this_status
;
687 if ((this_status
= switch_network_list_perform_add_cidr_token(list
, argv
[i
], ok
, token
, port
)) != SWITCH_STATUS_SUCCESS
) {
688 status
= this_status
;
693 status
= switch_network_list_perform_add_cidr_token(list
, cidr_str
, ok
, token
, port
);
696 switch_safe_free(cidr_str_dup
);
700 SWITCH_DECLARE(switch_status_t
) switch_network_list_add_cidr_token(switch_network_list_t
*list
, const char *cidr_str
, switch_bool_t ok
, const char *token
)
702 return switch_network_list_add_cidr_port_token(list
, cidr_str
, ok
, token
, NULL
);
705 SWITCH_DECLARE(switch_status_t
) switch_network_list_add_host_port_mask(switch_network_list_t
*list
, const char *host
, const char *mask_str
, switch_bool_t ok
, switch_network_port_range_p port
)
708 switch_network_node_t
*node
;
710 switch_inet_pton(AF_INET
, host
, &ip
);
711 switch_inet_pton(AF_INET
, mask_str
, &mask
);
713 node
= switch_core_alloc(list
->pool
, sizeof(*node
));
715 node
->ip
.v4
= ntohl(ip
.v4
);
716 node
->mask
.v4
= ntohl(mask
.v4
);
719 memcpy(&node
->port_range
, port
, sizeof(switch_network_port_range_t
));
722 /* http://graphics.stanford.edu/~seander/bithacks.html */
723 mask
.v4
= mask
.v4
- ((mask
.v4
>> 1) & 0x55555555);
724 mask
.v4
= (mask
.v4
& 0x33333333) + ((mask
.v4
>> 2) & 0x33333333);
725 node
->bits
= (((mask
.v4
+ (mask
.v4
>> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
727 node
->str
= switch_core_sprintf(list
->pool
, "%s:%s", host
, mask_str
);
729 node
->next
= list
->node_head
;
730 list
->node_head
= node
;
732 return SWITCH_STATUS_SUCCESS
;
735 SWITCH_DECLARE(switch_status_t
) switch_network_list_add_host_mask(switch_network_list_t
*list
, const char *host
, const char *mask_str
, switch_bool_t ok
)
737 return switch_network_list_add_host_port_mask(list
, host
, mask_str
, ok
, NULL
);
741 SWITCH_DECLARE(int) switch_parse_cidr(const char *string
, ip_t
*ip
, ip_t
*mask
, uint32_t *bitp
)
750 switch_copy_string(host
, string
, sizeof(host
)-1);
751 bit_str
= strchr(host
, '/');
758 bits
= atoi(bit_str
);
759 ipv6
= strchr(string
, ':');
762 if (bits
< 0 || bits
> 128) {
765 bits
= atoi(bit_str
);
766 switch_inet_pton(AF_INET6
, host
, (unsigned char *)ip
);
767 for (n
=bits
,i
=0 ;i
< 16; i
++){
769 maskv
->v6
.s6_addr
[i
] = 0xFF;
772 maskv
->v6
.s6_addr
[i
] = 0xFF & ~(0xFF >> n
);
775 maskv
->v6
.s6_addr
[i
] = 0x00;
779 if (bits
< 0 || bits
> 32) {
783 bits
= atoi(bit_str
);
784 switch_inet_pton(AF_INET
, host
, (unsigned char *)ip
);
785 ipv
->v4
= htonl(ipv
->v4
);
787 maskv
->v4
= 0xFFFFFFFF & ~(0xFFFFFFFF >> bits
);
795 SWITCH_DECLARE(char *) switch_find_end_paren(const char *s
, char open
, char close
)
797 const char *e
= NULL
;
800 while (s
&& *s
&& *s
== ' ') {
804 if (s
&& *s
== open
) {
806 for (e
= s
+ 1; e
&& *e
; e
++) {
807 if (*e
== open
&& open
!= close
) {
809 } else if (*e
== close
) {
818 return (e
&& *e
== close
) ? (char *) e
: NULL
;
821 SWITCH_DECLARE(switch_size_t
) switch_fd_read_line(int fd
, char *buf
, switch_size_t len
)
825 switch_size_t total
= 0;
828 while (total
+ 2 < len
&& (cur
= read(fd
, &c
, 1)) == 1) {
831 if (c
== '\r' || c
== '\n') {
841 #define DLINE_BLOCK_SIZE 1024
842 #define DLINE_MAX_SIZE 1048576
843 SWITCH_DECLARE(switch_size_t
) switch_fd_read_dline(int fd
, char **buf
, switch_size_t
*len
)
847 switch_size_t total
= 0;
849 switch_size_t ilen
= *len
;
852 *len
= ilen
= DLINE_BLOCK_SIZE
;
854 memset(data
, 0, ilen
);
858 while ((cur
= read(fd
, &c
, 1)) == 1) {
860 if (total
+ 2 >= ilen
) {
861 if (ilen
+ DLINE_BLOCK_SIZE
> DLINE_MAX_SIZE
) {
862 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "Single line limit reached!\n");
866 ilen
+= DLINE_BLOCK_SIZE
;
867 data
= realloc(data
, ilen
);
876 if (c
== '\r' || c
== '\n') {
891 SWITCH_DECLARE(switch_size_t
) switch_fp_read_dline(FILE *fd
, char **buf
, switch_size_t
*len
)
894 switch_size_t total
= 0;
896 switch_size_t ilen
= *len
;
899 *len
= ilen
= DLINE_BLOCK_SIZE
;
901 memset(data
, 0, ilen
);
905 //while ((c = fgetc(fd)) != EOF) {
907 while (fread(&c
, 1, 1, fd
) == 1) {
909 if (total
+ 2 >= ilen
) {
910 if (ilen
+ DLINE_BLOCK_SIZE
> DLINE_MAX_SIZE
) {
911 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "Single line limit reached!\n");
915 ilen
+= DLINE_BLOCK_SIZE
;
916 data
= realloc(data
, ilen
);
925 if (c
== '\r' || c
== '\n') {
938 SWITCH_DECLARE(char *) switch_amp_encode(char *s
, char *buf
, switch_size_t len
)
946 for (p
= s
; x
< len
; p
++) {
950 if (x
+ 6 > len
- 1) {
962 if (x
+ 6 > len
- 1) {
974 if (x
+ 5 > len
- 1) {
985 if (x
+ 4 > len
- 1) {
995 if (x
+ 4 > len
- 1) {
1005 if (x
+ 1 > len
- 1) {
1022 static const char switch_b64_table
[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1023 #define B64BUFFLEN 1024
1024 SWITCH_DECLARE(switch_status_t
) switch_b64_encode(unsigned char *in
, switch_size_t ilen
, unsigned char *out
, switch_size_t olen
)
1026 int y
= 0, bytes
= 0;
1028 unsigned int b
= 0, l
= 0;
1030 for (x
= 0; x
< ilen
; x
++) {
1031 b
= (b
<< 8) + in
[x
];
1035 out
[bytes
++] = switch_b64_table
[(b
>> (l
-= 6)) % 64];
1036 if (bytes
>= (int)olen
- 1) {
1042 /* out[bytes++] = '\n'; */
1048 out
[bytes
++] = switch_b64_table
[((b
% 16) << (6 - l
)) % 64];
1051 while (l
< 6 && bytes
< (int)olen
- 1) {
1052 out
[bytes
++] = '=', l
+= 2;
1060 return SWITCH_STATUS_SUCCESS
;
1063 SWITCH_DECLARE(switch_size_t
) switch_b64_decode(const char *in
, char *out
, switch_size_t olen
)
1067 int b
= 0, c
, l
= 0, i
;
1072 for (i
= 0; i
< 256; i
++) {
1076 for (i
= 0; i
< 64; i
++) {
1077 l64
[(int) switch_b64_table
[i
]] = (char) i
;
1080 for (ip
= in
; ip
&& *ip
; ip
++) {
1090 op
[ol
++] = (char) ((b
>> (l
-= 8)) % 256);
1091 if (ol
>= olen
- 1) {
1104 static int write_buf(int fd
, const char *buf
)
1107 int len
= (int) strlen(buf
);
1108 if (fd
&& write(fd
, buf
, len
) != len
) {
1116 SWITCH_DECLARE(switch_bool_t
) switch_simple_email(const char *to
,
1118 const char *headers
,
1119 const char *body
, const char *file
, const char *convert_cmd
, const char *convert_ext
)
1121 char *bound
= "XXXX_boundary_XXXX";
1122 const char *mime_type
= "audio/inline";
1123 char filename
[80], buf
[B64BUFFLEN
];
1124 int fd
= -1, ifd
= -1;
1125 int x
= 0, y
= 0, bytes
= 0, ilen
= 0;
1126 unsigned int b
= 0, l
= 0;
1127 unsigned char in
[B64BUFFLEN
];
1128 unsigned char out
[B64BUFFLEN
+ 512];
1129 char *dupfile
= NULL
, *ext
= NULL
;
1130 char *newfile
= NULL
;
1131 switch_bool_t rval
= SWITCH_FALSE
;
1132 const char *err
= NULL
;
1137 err
= "No to address specified";
1141 if (!zstr(file
) && !zstr(convert_cmd
) && !zstr(convert_ext
)) {
1142 if (strrchr(file
, '.')) {
1143 dupfile
= strdup(file
);
1144 if ((ext
= strrchr(dupfile
, '.'))) {
1146 newfile
= switch_mprintf("%s.%s", dupfile
, convert_ext
);
1151 char cmd
[1024] = "";
1152 switch_snprintf(cmd
, sizeof(cmd
), "%s %s %s", convert_cmd
, file
, newfile
);
1153 switch_system(cmd
, SWITCH_TRUE
);
1154 if (strcmp(file
, newfile
)) {
1157 switch_safe_free(newfile
);
1161 switch_safe_free(dupfile
);
1164 switch_snprintf(filename
, 80, "%s%smail.%d%04x", SWITCH_GLOBAL_dirs
.temp_dir
, SWITCH_PATH_SEPARATOR
, (int) switch_epoch_time_now(NULL
), rand() & 0xffff);
1166 if ((fd
= open(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644)) > -1) {
1168 if ((ifd
= open(file
, O_RDONLY
| O_BINARY
)) < 0) {
1169 rval
= SWITCH_FALSE
;
1170 err
= "Cannot open tmp file\n";
1175 if (!file
&& (!body
|| !switch_stristr("content-type", body
))) {
1180 switch_snprintf(buf
, B64BUFFLEN
, "MIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"%s\"\n", bound
);
1181 if (!write_buf(fd
, buf
)) {
1182 rval
= SWITCH_FALSE
;
1183 err
= "write error.";
1188 if (headers
&& !write_buf(fd
, headers
)) {
1189 rval
= SWITCH_FALSE
;
1190 err
= "write error.";
1194 if (!write_buf(fd
, "\n\n")) {
1195 rval
= SWITCH_FALSE
;
1196 err
= "write error.";
1201 if (body
&& switch_stristr("content-type", body
)) {
1202 switch_snprintf(buf
, B64BUFFLEN
, "--%s\n", bound
);
1204 switch_snprintf(buf
, B64BUFFLEN
, "--%s\nContent-Type: text/plain\n\n", bound
);
1206 if (!write_buf(fd
, buf
)) {
1207 rval
= SWITCH_FALSE
;
1208 err
= "write error.";
1214 if (!write_buf(fd
, body
)) {
1215 rval
= SWITCH_FALSE
;
1216 err
= "write error.";
1221 if (file
&& bound
) {
1222 const char *stipped_file
= switch_cut_path(file
);
1223 const char *new_type
;
1226 if ((ext
= strrchr(stipped_file
, '.'))) {
1228 if ((new_type
= switch_core_mime_ext2type(ext
))) {
1229 mime_type
= new_type
;
1233 switch_snprintf(buf
, B64BUFFLEN
,
1234 "\n\n--%s\nContent-Type: %s; name=\"%s\"\n"
1235 "Content-ID: <ATTACHED@freeswitch.org>\n"
1236 "Content-Transfer-Encoding: base64\n"
1237 "Content-Description: Sound attachment.\n"
1238 "Content-Disposition: attachment; filename=\"%s\"\n\n", bound
, mime_type
, stipped_file
, stipped_file
);
1239 if (!write_buf(fd
, buf
)) {
1240 rval
= SWITCH_FALSE
;
1241 err
= "write error.";
1245 while ((ilen
= read(ifd
, in
, B64BUFFLEN
))) {
1246 for (x
= 0; x
< ilen
; x
++) {
1247 b
= (b
<< 8) + in
[x
];
1250 out
[bytes
++] = switch_b64_table
[(b
>> (l
-= 6)) % 64];
1253 out
[bytes
++] = '\n';
1257 if (write(fd
, &out
, bytes
) != bytes
) {
1267 out
[bytes
++] = switch_b64_table
[((b
% 16) << (6 - l
)) % 64];
1271 out
[bytes
++] = '=', l
+= 2;
1273 if (write(fd
, &out
, bytes
) != bytes
) {
1280 switch_snprintf(buf
, B64BUFFLEN
, "\n\n--%s--\n.\n", bound
);
1282 if (!write_buf(fd
, buf
)) {
1283 rval
= SWITCH_FALSE
;
1284 err
= "write error.";
1296 from
= "freeswitch";
1300 char *to_arg
= switch_util_quote_shell_arg(to
);
1301 char *from_arg
= switch_util_quote_shell_arg(from
);
1303 switch_snprintf(buf
, B64BUFFLEN
, "\"\"%s\" -f %s %s %s < \"%s\"\"", runtime
.mailer_app
, from_arg
, runtime
.mailer_app_args
, to_arg
, filename
);
1305 switch_snprintf(buf
, B64BUFFLEN
, "/bin/cat %s | %s -f %s %s %s", filename
, runtime
.mailer_app
, from_arg
, runtime
.mailer_app_args
, to_arg
);
1307 switch_safe_free(to_arg
); switch_safe_free(from_arg
);
1309 if (switch_system(buf
, SWITCH_TRUE
) < 0) {
1310 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Unable to execute command: %s\n", buf
);
1311 err
= "execute error";
1312 rval
= SWITCH_FALSE
;
1317 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG
, "Emailed file [%s] to [%s]\n", filename
, to
);
1319 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG
, "Emailed data to [%s]\n", to
);
1331 if (!zstr_buf(filename
) && unlink(filename
) != 0) {
1332 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "Failed to delete file [%s]\n", filename
);
1345 if (rval
!= SWITCH_TRUE
) {
1346 if (zstr(err
)) err
= "Unknown Error";
1348 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "EMAIL NOT SENT, error [%s]\n", err
);
1354 SWITCH_DECLARE(switch_bool_t
) switch_is_lan_addr(const char *ip
)
1357 return SWITCH_FALSE
;
1359 return (strncmp(ip
, "10.", 3) && /* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */
1360 strncmp(ip
, "192.168.", 8) && /* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */
1361 strncmp(ip
, "127.", 4) && /* 127.0.0.0 - 127.255.255.255 (127/8 prefix) */
1362 strncmp(ip
, "255.", 4) &&
1363 strncmp(ip
, "0.", 2) &&
1364 strncmp(ip
, "1.", 2) &&
1365 strncmp(ip
, "2.", 2) &&
1366 strncmp(ip
, "172.16.", 7) && /* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */
1367 strncmp(ip
, "172.17.", 7) &&
1368 strncmp(ip
, "172.18.", 7) &&
1369 strncmp(ip
, "172.19.", 7) &&
1370 strncmp(ip
, "172.20.", 7) &&
1371 strncmp(ip
, "172.21.", 7) &&
1372 strncmp(ip
, "172.22.", 7) &&
1373 strncmp(ip
, "172.23.", 7) &&
1374 strncmp(ip
, "172.24.", 7) &&
1375 strncmp(ip
, "172.25.", 7) &&
1376 strncmp(ip
, "172.26.", 7) &&
1377 strncmp(ip
, "172.27.", 7) &&
1378 strncmp(ip
, "172.28.", 7) &&
1379 strncmp(ip
, "172.29.", 7) &&
1380 strncmp(ip
, "172.30.", 7) &&
1381 strncmp(ip
, "172.31.", 7) &&
1382 strncmp(ip
, "192.0.2.", 8) && /* 192.0.2.0 - 192.0.2.255 (192.0.2/24 prefix) */
1383 strncmp(ip
, "169.254.", 8) /* 169.254.0.0 - 169.254.255.255 (169.254/16 prefix) */
1384 )? SWITCH_FALSE
: SWITCH_TRUE
;
1387 SWITCH_DECLARE(switch_bool_t
) switch_ast2regex(const char *pat
, char *rbuf
, size_t len
)
1389 const char *p
= pat
;
1392 return SWITCH_FALSE
;
1395 memset(rbuf
, 0, len
);
1397 *(rbuf
+ strlen(rbuf
)) = '^';
1401 strncat(rbuf
, "[2-9]", len
- strlen(rbuf
));
1402 } else if (*p
== 'X') {
1403 strncat(rbuf
, "[0-9]", len
- strlen(rbuf
));
1404 } else if (*p
== 'Z') {
1405 strncat(rbuf
, "[1-9]", len
- strlen(rbuf
));
1406 } else if (*p
== '.') {
1407 strncat(rbuf
, ".*", len
- strlen(rbuf
));
1408 } else if (strlen(rbuf
) < len
- 1) {
1409 *(rbuf
+ strlen(rbuf
)) = *p
;
1413 *(rbuf
+ strlen(rbuf
)) = '$';
1415 return strcmp(pat
, rbuf
) ? SWITCH_TRUE
: SWITCH_FALSE
;
1418 SWITCH_DECLARE(char *) switch_replace_char(char *str
, char from
, char to
, switch_bool_t dup
)
1429 for (; p
&& *p
; p
++) {
1438 SWITCH_DECLARE(char *) switch_pool_strip_whitespace(switch_memory_pool_t
*pool
, const char *str
)
1440 const char *sp
= str
;
1445 return switch_core_strdup(pool
, SWITCH_BLANK_STRING
);
1448 while ((*sp
== 13 ) || (*sp
== 10 ) || (*sp
== 9 ) || (*sp
== 32) || (*sp
== 11) ) {
1453 return switch_core_strdup(pool
, SWITCH_BLANK_STRING
);
1456 s
= switch_core_strdup(pool
, sp
);
1459 if ((len
= strlen(s
)) > 0) {
1462 while ((p
>= s
) && ((*p
== 13 ) || (*p
== 10 ) || (*p
== 9 ) || (*p
== 32) || (*p
== 11))) {
1470 SWITCH_DECLARE(char *) switch_strip_whitespace(const char *str
)
1472 const char *sp
= str
;
1477 return strdup(SWITCH_BLANK_STRING
);
1480 while ((*sp
== 13 ) || (*sp
== 10 ) || (*sp
== 9 ) || (*sp
== 32) || (*sp
== 11) ) {
1485 return strdup(SWITCH_BLANK_STRING
);
1491 if ((len
= strlen(s
)) > 0) {
1494 while ((p
>= s
) && ((*p
== 13 ) || (*p
== 10 ) || (*p
== 9 ) || (*p
== 32) || (*p
== 11))) {
1502 SWITCH_DECLARE(char *) switch_strip_spaces(char *str
, switch_bool_t dup
)
1509 return dup
? strdup(SWITCH_BLANK_STRING
) : sp
;
1512 while (*sp
== ' ') {
1527 if ((len
= strlen(s
)) > 0) {
1530 while (p
&& *p
&& (p
>= s
) && *p
== ' ') {
1538 SWITCH_DECLARE(char *) switch_strip_commas(char *in
, char *out
, switch_size_t len
)
1540 char *p
= in
, *q
= out
;
1542 switch_size_t x
= 0;
1544 for (; p
&& *p
; p
++) {
1545 if ((*p
> 47 && *p
< 58)) {
1552 } else if (*p
!= ',') {
1561 SWITCH_DECLARE(char *) switch_strip_nonnumerics(char *in
, char *out
, switch_size_t len
)
1563 char *p
= in
, *q
= out
;
1565 switch_size_t x
= 0;
1566 /* valid are 0 - 9, period (.), minus (-), and plus (+) - remove all others */
1567 for (; p
&& *p
; p
++) {
1568 if ((*p
> 47 && *p
< 58) || *p
== '.' || *p
== '-' || *p
== '+') {
1581 SWITCH_DECLARE(char *) switch_separate_paren_args(char *str
)
1586 if ((args
= strchr(str
, '('))) {
1597 } else if (br
> 1 && *e
== ')') {
1599 } else if (br
== 1 && *e
== ')') {
1610 SWITCH_DECLARE(switch_bool_t
) switch_is_number(const char *str
)
1613 switch_bool_t r
= SWITCH_TRUE
;
1615 if (*str
== '-' || *str
== '+') {
1619 for (p
= str
; p
&& *p
; p
++) {
1620 if (!(*p
== '.' || (*p
> 47 && *p
< 58))) {
1629 SWITCH_DECLARE(switch_bool_t
) switch_is_leading_number(const char *str
)
1632 switch_bool_t r
= SWITCH_FALSE
;
1634 if (*str
== '-' || *str
== '+') {
1638 for (p
= str
; p
&& *p
; p
++) {
1639 if ((*p
== '.' || (*p
> 47 && *p
< 58))) {
1648 SWITCH_DECLARE(const char *) switch_stristr(const char *instr
, const char *str
)
1651 ** Rev History: 16/07/97 Greg Thayer Optimized
1652 ** 07/04/95 Bob Stout ANSI-fy
1653 ** 02/03/94 Fred Cole Original
1654 ** 09/01/03 Bob Stout Bug fix (lines 40-41) per Fred Bulback
1656 ** Hereby donated to public domain.
1658 const char *pptr
, *sptr
, *start
;
1663 for (start
= str
; *start
; start
++) {
1664 /* find start of pattern in string */
1665 for (; ((*start
) && (switch_toupper(*start
) != switch_toupper(*instr
))); start
++);
1673 while (switch_toupper(*sptr
) == switch_toupper(*pptr
)) {
1677 /* if end of pattern then pattern was found */
1688 #ifdef HAVE_GETIFADDRS
1689 #include <ifaddrs.h>
1690 static int get_netmask(struct sockaddr_in
*me
, int *mask
)
1692 struct ifaddrs
*ifaddrs
, *i
= NULL
;
1694 if (!me
|| getifaddrs(&ifaddrs
) < 0) {
1698 for (i
= ifaddrs
; i
; i
= i
->ifa_next
) {
1699 struct sockaddr_in
*s
= (struct sockaddr_in
*) i
->ifa_addr
;
1700 struct sockaddr_in
*m
= (struct sockaddr_in
*) i
->ifa_netmask
;
1702 if (s
&& m
&& s
->sin_family
== AF_INET
&& s
->sin_addr
.s_addr
== me
->sin_addr
.s_addr
) {
1703 *mask
= m
->sin_addr
.s_addr
;
1704 freeifaddrs(ifaddrs
);
1709 freeifaddrs(ifaddrs
);
1713 #elif defined(__linux__)
1715 #include <sys/ioctl.h>
1717 static int get_netmask(struct sockaddr_in
*me
, int *mask
)
1720 static struct ifreq ifreqs
[20] = { {{{0}}} };
1721 struct ifconf ifconf
;
1726 memset(&ifconf
, 0, sizeof(ifconf
));
1727 ifconf
.ifc_buf
= (char *) (ifreqs
);
1728 ifconf
.ifc_len
= sizeof(ifreqs
);
1731 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
1735 if (ioctl(sock
, SIOCGIFCONF
, (char *) &ifconf
) < 0) {
1739 nifaces
= ifconf
.ifc_len
/ sizeof(struct ifreq
);
1741 for (i
= 0; i
< nifaces
; i
++) {
1742 struct sockaddr_in
*sin
= NULL
;
1745 ioctl(sock
, SIOCGIFADDR
, &ifreqs
[i
]);
1746 sin
= (struct sockaddr_in
*) &ifreqs
[i
].ifr_addr
;
1749 if (ip
.s_addr
== me
->sin_addr
.s_addr
) {
1750 ioctl(sock
, SIOCGIFNETMASK
, &ifreqs
[i
]);
1751 sin
= (struct sockaddr_in
*) &ifreqs
[i
].ifr_addr
;
1752 /* mask = sin->sin_addr; */
1753 *mask
= sin
->sin_addr
.s_addr
;
1767 #elif defined(WIN32)
1769 static int get_netmask(struct sockaddr_in
*me
, int *mask
)
1771 SOCKET sock
= WSASocket(AF_INET
, SOCK_DGRAM
, 0, 0, 0, 0);
1772 INTERFACE_INFO interfaces
[20];
1773 unsigned long bytes
;
1774 int interface_count
, x
;
1779 if (sock
== SOCKET_ERROR
) {
1783 if (WSAIoctl(sock
, SIO_GET_INTERFACE_LIST
, 0, 0, &interfaces
, sizeof(interfaces
), &bytes
, 0, 0) == SOCKET_ERROR
) {
1788 interface_count
= bytes
/ sizeof(INTERFACE_INFO
);
1790 for (x
= 0; x
< interface_count
; ++x
) {
1791 struct sockaddr_in
*addr
= (struct sockaddr_in
*) &(interfaces
[x
].iiAddress
);
1793 if (addr
->sin_addr
.s_addr
== me
->sin_addr
.s_addr
) {
1794 struct sockaddr_in
*netmask
= (struct sockaddr_in
*) &(interfaces
[x
].iiNetmask
);
1795 *mask
= netmask
->sin_addr
.s_addr
;
1808 static int get_netmask(struct sockaddr_in
*me
, int *mask
)
1816 SWITCH_DECLARE(switch_status_t
) switch_resolve_host(const char *host
, char *buf
, size_t buflen
)
1819 struct addrinfo
*ai
;
1821 if (getaddrinfo(host
, 0, 0, &ai
)) {
1822 return SWITCH_STATUS_FALSE
;
1825 get_addr(buf
, buflen
, ai
->ai_addr
, sizeof(struct sockaddr_storage
));
1829 return SWITCH_STATUS_SUCCESS
;
1833 SWITCH_DECLARE(switch_status_t
) switch_find_local_ip(char *buf
, int len
, int *mask
, int family
)
1835 switch_status_t status
= SWITCH_STATUS_FALSE
;
1837 char *force_local_ip_v4
= switch_core_get_variable_dup("force_local_ip_v4");
1838 char *force_local_ip_v6
= switch_core_get_variable_dup("force_local_ip_v6");
1842 SOCKADDR_STORAGE l_address
;
1844 struct addrinfo
*address_info
;
1851 int tmp_socket
= -1, on
= 1;
1857 if (force_local_ip_v4
) {
1858 switch_copy_string(buf
, force_local_ip_v4
, len
);
1859 switch_safe_free(force_local_ip_v4
);
1860 switch_safe_free(force_local_ip_v6
);
1861 return SWITCH_STATUS_SUCCESS
;
1864 if (force_local_ip_v6
) {
1865 switch_copy_string(buf
, force_local_ip_v6
, len
);
1866 switch_safe_free(force_local_ip_v4
);
1867 switch_safe_free(force_local_ip_v6
);
1868 return SWITCH_STATUS_SUCCESS
;
1871 switch_safe_free(force_local_ip_v4
);
1872 switch_safe_free(force_local_ip_v6
);
1883 switch_copy_string(buf
, "127.0.0.1", len
);
1884 base
= "82.45.148.209";
1887 switch_copy_string(buf
, "::1", len
);
1888 base
= "2001:503:BA3E::2:30"; /* DNS Root server A */
1896 tmp_socket
= socket(family
, SOCK_DGRAM
, 0);
1898 getaddrinfo(base
, NULL
, NULL
, &address_info
);
1900 if (!address_info
|| WSAIoctl(tmp_socket
,
1901 SIO_ROUTING_INTERFACE_QUERY
,
1902 address_info
->ai_addr
, (DWORD
) address_info
->ai_addrlen
, &l_address
, sizeof(l_address
), (LPDWORD
) & l_address_len
, NULL
,
1905 closesocket(tmp_socket
);
1907 freeaddrinfo(address_info
);
1912 closesocket(tmp_socket
);
1913 freeaddrinfo(address_info
);
1915 if (!getnameinfo((const struct sockaddr
*) &l_address
, l_address_len
, buf
, len
, NULL
, 0, NI_NUMERICHOST
)) {
1916 status
= SWITCH_STATUS_SUCCESS
;
1918 get_netmask((struct sockaddr_in
*) &l_address
, mask
);
1926 struct sockaddr_in iface_out
;
1927 struct sockaddr_in remote
;
1928 memset(&remote
, 0, sizeof(struct sockaddr_in
));
1930 remote
.sin_family
= AF_INET
;
1931 remote
.sin_addr
.s_addr
= inet_addr(base
);
1932 remote
.sin_port
= htons(4242);
1934 memset(&iface_out
, 0, sizeof(iface_out
));
1935 if ( (tmp_socket
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1 ) {
1939 if (setsockopt(tmp_socket
, SOL_SOCKET
, SO_BROADCAST
, &on
, sizeof(on
)) == -1) {
1943 if (connect(tmp_socket
, (struct sockaddr
*) &remote
, sizeof(struct sockaddr_in
)) == -1) {
1947 ilen
= sizeof(iface_out
);
1948 if (getsockname(tmp_socket
, (struct sockaddr
*) &iface_out
, &ilen
) == -1) {
1952 if (iface_out
.sin_addr
.s_addr
== 0) {
1956 switch_copy_string(buf
, get_addr(abuf
, sizeof(abuf
), (struct sockaddr
*) &iface_out
, sizeof(struct sockaddr_storage
)), len
);
1958 get_netmask((struct sockaddr_in
*) &iface_out
, mask
);
1961 status
= SWITCH_STATUS_SUCCESS
;
1966 struct sockaddr_in6 iface_out
;
1967 struct sockaddr_in6 remote
;
1968 memset(&remote
, 0, sizeof(struct sockaddr_in6
));
1970 remote
.sin6_family
= AF_INET6
;
1971 switch_inet_pton(AF_INET6
, base
, &remote
.sin6_addr
);
1972 remote
.sin6_port
= htons(4242);
1974 memset(&iface_out
, 0, sizeof(iface_out
));
1975 if ( (tmp_socket
= socket(AF_INET6
, SOCK_DGRAM
, 0)) == -1 ) {
1979 if (connect(tmp_socket
, (struct sockaddr
*) &remote
, sizeof(remote
)) == -1) {
1983 ilen
= sizeof(iface_out
);
1984 if (getsockname(tmp_socket
, (struct sockaddr
*) &iface_out
, &ilen
) == -1) {
1988 inet_ntop(AF_INET6
, (const void *) &iface_out
.sin6_addr
, buf
, len
- 1);
1989 status
= SWITCH_STATUS_SUCCESS
;
1995 if (tmp_socket
> 0) {
2003 #ifdef HAVE_GETIFADDRS
2004 # include <ifaddrs.h>
2005 # include <net/if.h>
2007 SWITCH_DECLARE(switch_status_t
) switch_find_interface_ip(char *buf
, int len
, int *mask
, const char *ifname
, int family
)
2009 switch_status_t status
= SWITCH_STATUS_FALSE
;
2011 #ifdef HAVE_GETIFADDRS
2013 struct ifaddrs
*addrs
, *addr
;
2016 for(addr
= addrs
; addr
; addr
= addr
->ifa_next
)
2018 if (!(addr
->ifa_flags
& IFF_UP
)) continue; // Address is not UP
2019 if (!addr
->ifa_addr
) continue; // No address set
2020 if (!addr
->ifa_netmask
) continue; // No netmask set
2021 if (family
!= AF_UNSPEC
&& addr
->ifa_addr
->sa_family
!= family
) continue; // Not the address family we're looking for
2022 if (strcmp(addr
->ifa_name
, ifname
)) continue; // Not the interface we're looking for
2024 switch(addr
->ifa_addr
->sa_family
) {
2026 inet_ntop(AF_INET
, &( ((struct sockaddr_in
*)(addr
->ifa_addr
))->sin_addr
), buf
, len
- 1);
2029 inet_ntop(AF_INET6
, &( ((struct sockaddr_in6
*)(addr
->ifa_addr
))->sin6_addr
), buf
, len
- 1);
2035 if (mask
&& addr
->ifa_netmask
->sa_family
== AF_INET
) {
2036 *mask
= ((struct sockaddr_in
*)(addr
->ifa_addr
))->sin_addr
.s_addr
;
2039 status
= SWITCH_STATUS_SUCCESS
;
2044 #elif defined(__linux__)
2046 // TODO Not implemented, contributions welcome.
2048 #elif defined(WIN32)
2050 // TODO Not implemented, contributions welcome.
2058 SWITCH_DECLARE(switch_time_t
) switch_str_time(const char *in
)
2060 switch_time_exp_t tm
= { 0 }, local_tm
= { 0 };
2061 int proceed
= 0, ovector
[30], time_only
= 0;
2062 switch_regex_t
*re
= NULL
;
2063 char replace
[1024] = "";
2064 switch_time_t ret
= 0, local_time
= 0;
2065 char *pattern
= "^(\\d+)-(\\d+)-(\\d+)\\s*(\\d*):{0,1}(\\d*):{0,1}(\\d*)";
2066 char *pattern2
= "^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})";
2067 char *pattern3
= "^(\\d*):{0,1}(\\d*):{0,1}(\\d*)$";
2069 switch_time_exp_lt(&tm
, switch_micro_time_now());
2072 if ((time_only
= switch_regex_perform(in
, pattern3
, &re
, ovector
, sizeof(ovector
) / sizeof(ovector
[0])))) {
2077 tm
.tm_year
= tm
.tm_mon
= tm
.tm_mday
= tm
.tm_hour
= tm
.tm_min
= tm
.tm_sec
= tm
.tm_usec
= 0;
2079 if (!(proceed
= switch_regex_perform(in
, pattern
, &re
, ovector
, sizeof(ovector
) / sizeof(ovector
[0])))) {
2080 switch_regex_safe_free(re
);
2081 proceed
= switch_regex_perform(in
, pattern2
, &re
, ovector
, sizeof(ovector
) / sizeof(ovector
[0]));
2085 if (proceed
|| time_only
) {
2087 if (time_only
> 1) {
2088 switch_regex_copy_substring(in
, ovector
, time_only
, 1, replace
, sizeof(replace
));
2089 tm
.tm_hour
= atoi(replace
);
2092 if (time_only
> 2) {
2093 switch_regex_copy_substring(in
, ovector
, time_only
, 2, replace
, sizeof(replace
));
2094 tm
.tm_min
= atoi(replace
);
2097 if (time_only
> 3) {
2098 switch_regex_copy_substring(in
, ovector
, time_only
, 3, replace
, sizeof(replace
));
2099 tm
.tm_sec
= atoi(replace
);
2103 switch_regex_copy_substring(in
, ovector
, proceed
, 1, replace
, sizeof(replace
));
2104 tm
.tm_year
= atoi(replace
) - 1900;
2108 switch_regex_copy_substring(in
, ovector
, proceed
, 2, replace
, sizeof(replace
));
2109 tm
.tm_mon
= atoi(replace
) - 1;
2113 switch_regex_copy_substring(in
, ovector
, proceed
, 3, replace
, sizeof(replace
));
2114 tm
.tm_mday
= atoi(replace
);
2118 switch_regex_copy_substring(in
, ovector
, proceed
, 4, replace
, sizeof(replace
));
2119 tm
.tm_hour
= atoi(replace
);
2123 switch_regex_copy_substring(in
, ovector
, proceed
, 5, replace
, sizeof(replace
));
2124 tm
.tm_min
= atoi(replace
);
2128 switch_regex_copy_substring(in
, ovector
, proceed
, 6, replace
, sizeof(replace
));
2129 tm
.tm_sec
= atoi(replace
);
2132 switch_regex_safe_free(re
);
2134 switch_time_exp_get(&local_time
, &tm
);
2135 switch_time_exp_lt(&local_tm
, local_time
);
2136 tm
.tm_isdst
= local_tm
.tm_isdst
;
2137 tm
.tm_gmtoff
= local_tm
.tm_gmtoff
;
2139 switch_time_exp_gmt_get(&ret
, &tm
);
2143 switch_regex_safe_free(re
);
2148 SWITCH_DECLARE(const char *) switch_priority_name(switch_priority_t priority
)
2150 switch (priority
) { /*lol */
2151 case SWITCH_PRIORITY_NORMAL
:
2153 case SWITCH_PRIORITY_LOW
:
2155 case SWITCH_PRIORITY_HIGH
:
2162 static char RFC2833_CHARS
[] = "0123456789*#ABCDF";
2165 /* Copyright (c) 1996 by Internet Software Consortium.
2167 * Permission to use, copy, modify, and distribute this software for any
2168 * purpose with or without fee is hereby granted, provided that the above
2169 * copyright notice and this permission notice appear in all copies.
2171 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
2172 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
2173 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
2174 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
2175 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
2176 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
2177 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2187 #include <sys/types.h>
2190 * WARNING: Don't even consider trying to compile this on a system where
2191 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
2194 static const char *switch_inet_ntop4(const unsigned char *src
, char *dst
, size_t size
);
2196 static const char *switch_inet_ntop6(const unsigned char *src
, char *dst
, size_t size
);
2200 * inet_ntop(af, src, dst, size)
2201 * convert a network format address to presentation format.
2203 * pointer to presentation format address (`dst'), or NULL (see errno).
2207 SWITCH_DECLARE(const char *) switch_inet_ntop(int af
, void const *src
, char *dst
, size_t size
)
2212 return switch_inet_ntop4(src
, dst
, size
);
2215 return switch_inet_ntop6(src
, dst
, size
);
2224 * inet_ntop4(src, dst, size)
2225 * format an IPv4 address, more or less like inet_ntoa()
2227 * `dst' (as a const)
2229 * (1) uses no statics
2230 * (2) takes a unsigned char* not an in_addr as input
2234 static const char *switch_inet_ntop4(const unsigned char *src
, char *dst
, size_t size
)
2236 static const char fmt
[] = "%u.%u.%u.%u";
2237 char tmp
[sizeof "255.255.255.255"];
2239 if (switch_snprintf(tmp
, sizeof tmp
, fmt
, src
[0], src
[1], src
[2], src
[3]) >= (int) size
) {
2243 return strcpy(dst
, tmp
);
2246 #if HAVE_SIN6 || defined(NTDDI_VERSION)
2248 * inet_ntop6(src, dst, size)
2249 * convert IPv6 binary address into presentation (printable) format
2253 static const char *switch_inet_ntop6(unsigned char const *src
, char *dst
, size_t size
)
2256 * Note that int32_t and int16_t need only be "at least" large enough
2257 * to contain a value of the specified size. On some systems, like
2258 * Crays, there is no such thing as an integer variable with 16 bits.
2259 * Keep this in mind if you think this function should have been coded
2260 * to use pointer overlays. All the world's not a VAX.
2262 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp
;
2268 unsigned int words
[8];
2273 * Copy the input (bytewise) array into a wordwise array.
2274 * Find the longest run of 0x00's in src[] for :: shorthanding.
2276 for (i
= 0; i
< 16; i
+= 2)
2277 words
[i
/ 2] = (src
[i
] << 8) | (src
[i
+ 1]);
2280 for (i
= 0; i
< 8; i
++) {
2281 if (words
[i
] == 0) {
2283 cur
.base
= i
, cur
.len
= 1;
2287 if (cur
.base
!= -1) {
2288 if (best
.base
== -1 || cur
.len
> best
.len
)
2294 if (cur
.base
!= -1) {
2295 if (best
.base
== -1 || cur
.len
> best
.len
)
2298 if (best
.base
!= -1 && best
.len
< 2)
2302 * Format the result.
2305 for (i
= 0; i
< 8; i
++) {
2306 /* Are we inside the best run of 0x00's? */
2307 if (best
.base
!= -1 && i
>= best
.base
&& i
< (best
.base
+ best
.len
)) {
2312 /* Are we following an initial run of 0x00s or any real hex? */
2315 /* Is this address an encapsulated IPv4? */
2316 if (i
== 6 && best
.base
== 0 && (best
.len
== 6 || (best
.len
== 5 && words
[5] == 0xffff))) {
2317 if (!switch_inet_ntop4(src
+ 12, tp
, sizeof tmp
- (tp
- tmp
)))
2322 tp
+= sprintf(tp
, "%x", words
[i
]);
2324 /* Was it a trailing run of 0x00's? */
2325 if (best
.base
!= -1 && (best
.base
+ best
.len
) == 8)
2330 * Check for overflow, copy, and we're done.
2332 if ((size_t) (tp
- tmp
) >= size
) {
2336 return strcpy(dst
, tmp
);
2342 SWITCH_DECLARE(int) get_addr_int(switch_sockaddr_t
*sa
)
2344 struct sockaddr_in
*s
= (struct sockaddr_in
*) &sa
->sa
;
2346 return ntohs((unsigned short) s
->sin_addr
.s_addr
);
2349 SWITCH_DECLARE(int) switch_cmp_addr(switch_sockaddr_t
*sa1
, switch_sockaddr_t
*sa2
, switch_bool_t ip_only
)
2351 struct sockaddr_in
*s1
;
2352 struct sockaddr_in
*s2
;
2354 struct sockaddr_in6
*s16
;
2355 struct sockaddr_in6
*s26
;
2357 struct sockaddr
*ss1
;
2358 struct sockaddr
*ss2
;
2363 s1
= (struct sockaddr_in
*) &sa1
->sa
;
2364 s2
= (struct sockaddr_in
*) &sa2
->sa
;
2366 s16
= (struct sockaddr_in6
*) &sa1
->sa
;
2367 s26
= (struct sockaddr_in6
*) &sa2
->sa
;
2369 ss1
= (struct sockaddr
*) &sa1
->sa
;
2370 ss2
= (struct sockaddr
*) &sa2
->sa
;
2372 if (ss1
->sa_family
!= ss2
->sa_family
)
2375 switch (ss1
->sa_family
) {
2378 return (s1
->sin_addr
.s_addr
== s2
->sin_addr
.s_addr
);
2380 return (s1
->sin_addr
.s_addr
== s2
->sin_addr
.s_addr
&& s1
->sin_port
== s2
->sin_port
);
2383 if (s16
->sin6_addr
.s6_addr
&& s26
->sin6_addr
.s6_addr
) {
2387 if (s16
->sin6_port
!= s26
->sin6_port
) return 0;
2390 for (i
= 0; i
< 4; i
++) {
2391 if (*((int32_t *) s16
->sin6_addr
.s6_addr
+ i
) != *((int32_t *) s26
->sin6_addr
.s6_addr
+ i
)) return 0;
2402 SWITCH_DECLARE(int) switch_cp_addr(switch_sockaddr_t
*sa1
, switch_sockaddr_t
*sa2
)
2404 struct sockaddr_in
*s1
;
2405 struct sockaddr_in
*s2
;
2407 struct sockaddr_in6
*s16
;
2408 struct sockaddr_in6
*s26
;
2410 struct sockaddr
*ss1
;
2411 //struct sockaddr *ss2;
2416 s1
= (struct sockaddr_in
*) &sa1
->sa
;
2417 s2
= (struct sockaddr_in
*) &sa2
->sa
;
2419 s16
= (struct sockaddr_in6
*) &sa1
->sa
;
2420 s26
= (struct sockaddr_in6
*) &sa2
->sa
;
2422 ss1
= (struct sockaddr
*) &sa1
->sa
;
2423 //ss2 = (struct sockaddr *) &sa2->sa;
2425 sa1
->port
= sa2
->port
;
2426 sa1
->family
= sa2
->family
;
2428 sa1
->sa
.sin
.sin_family
= sa2
->family
;
2430 switch (ss1
->sa_family
) {
2432 s1
->sin_addr
.s_addr
= s2
->sin_addr
.s_addr
;
2433 s1
->sin_port
= s2
->sin_port
;
2437 if (s16
->sin6_addr
.s6_addr
&& s26
->sin6_addr
.s6_addr
) {
2440 s16
->sin6_port
= s26
->sin6_port
;
2442 for (i
= 0; i
< 4; i
++) {
2443 *((int32_t *) s16
->sin6_addr
.s6_addr
+ i
) = *((int32_t *) s26
->sin6_addr
.s6_addr
+ i
);
2453 SWITCH_DECLARE(char *) get_addr6(char *buf
, switch_size_t len
, struct sockaddr_in6
*sa
, socklen_t salen
)
2459 #if defined(NTDDI_VERSION)
2460 switch_inet_ntop6((unsigned char*)&(sa
->sin6_addr
), buf
, len
);
2462 inet_ntop(AF_INET6
, &(sa
->sin6_addr
), buf
, len
);
2469 SWITCH_DECLARE(char *) get_addr(char *buf
, switch_size_t len
, struct sockaddr
*sa
, socklen_t salen
)
2475 getnameinfo(sa
, salen
, buf
, (socklen_t
) len
, NULL
, 0, NI_NUMERICHOST
);
2480 SWITCH_DECLARE(unsigned short) get_port(struct sockaddr
*sa
)
2482 unsigned short port
= 0;
2484 switch (sa
->sa_family
) {
2486 port
= ntohs(((struct sockaddr_in
*) sa
)->sin_port
);
2489 port
= ntohs(((struct sockaddr_in6
*) sa
)->sin6_port
);
2496 SWITCH_DECLARE(int) switch_build_uri(char *uri
, switch_size_t size
, const char *scheme
, const char *user
, const switch_sockaddr_t
*sa
, int flags
)
2498 char host
[NI_MAXHOST
], serv
[NI_MAXSERV
];
2499 struct sockaddr_in6 si6
;
2500 const struct sockaddr
*addr
;
2503 if (flags
& SWITCH_URI_NO_SCOPE
&& sa
->family
== AF_INET6
) {
2504 memcpy(&si6
, &sa
->sa
, sa
->salen
);
2505 si6
.sin6_scope_id
= 0;
2507 addr
= (const struct sockaddr
*) &si6
;
2509 addr
= (const struct sockaddr
*) (intptr_t) & sa
->sa
;
2512 if (getnameinfo(addr
, sa
->salen
, host
, sizeof(host
), serv
, sizeof(serv
),
2513 ((flags
& SWITCH_URI_NUMERIC_HOST
) ? NI_NUMERICHOST
: 0) | ((flags
& SWITCH_URI_NUMERIC_PORT
) ? NI_NUMERICSERV
: 0)) != 0) {
2517 colon
= strchr(host
, ':');
2519 return switch_snprintf(uri
, size
, "%s:%s%s%s%s%s%s%s", scheme
,
2520 user
? user
: "", user
? "@" : "", colon
? "[" : "", host
, colon
? "]" : "", serv
[0] ? ":" : "", serv
[0] ? serv
: "");
2523 SWITCH_DECLARE(char) switch_rfc2833_to_char(int event
)
2525 if (event
> -1 && event
< (int32_t) sizeof(RFC2833_CHARS
)) {
2526 return RFC2833_CHARS
[event
];
2531 SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key
)
2534 unsigned char counter
= 0;
2536 key
= (char) switch_toupper(key
);
2537 for (c
= RFC2833_CHARS
; *c
; c
++) {
2546 SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t
*pool
, char *in
, const char *delim
, char esc
)
2550 int count
= 1, i
= 0;
2568 data
= switch_core_alloc(pool
, strlen(in
) + count
);
2585 /* Helper function used when separating strings to unescape a character. The
2586 supported characters are:
2593 Any other character is returned as it was received. */
2594 static char unescape_char(char escaped
)
2612 unescaped
= escaped
;
2617 SWITCH_DECLARE(char *) switch_escape_string(const char *in
, char *out
, switch_size_t outlen
)
2622 for (p
= in
; *p
; p
++) {
2655 SWITCH_DECLARE(char *) switch_escape_string_pool(const char *in
, switch_memory_pool_t
*pool
)
2657 size_t len
= strlen(in
) * 2 + 1;
2658 char *buf
= switch_core_alloc(pool
, len
);
2659 return switch_escape_string(in
, buf
, len
);
2662 /* Helper function used when separating strings to remove quotes, leading /
2663 trailing spaces, and to convert escaped characters. */
2664 static char *cleanup_separated_string(char *str
, char delim
)
2670 int inside_quotes
= 0;
2672 /* Skip initial whitespace */
2673 for (ptr
= str
; *ptr
== ' '; ++ptr
) {
2676 for (start
= dest
= ptr
; *ptr
; ++ptr
) {
2680 if (*ptr
== ESCAPE_META
) {
2682 if (e
== '\'' || e
== '"' || (delim
&& e
== delim
) || e
== ESCAPE_META
|| (e
= unescape_char(*(ptr
+ 1))) != *(ptr
+ 1)) {
2690 if (*ptr
== '\'' && (inside_quotes
|| strchr(ptr
+1, '\''))) {
2691 if ((inside_quotes
= (1 - inside_quotes
))) {
2696 if (*ptr
!= ' ' || inside_quotes
) {
2709 SWITCH_DECLARE(unsigned int) switch_separate_string_string(char *buf
, char *delim
, char **array
, unsigned int arraylen
)
2711 unsigned int count
= 0;
2713 size_t dlen
= strlen(delim
);
2715 array
[count
++] = buf
;
2717 while (count
< arraylen
&& array
[count
- 1]) {
2718 if ((d
= strstr(array
[count
- 1], delim
))) {
2729 /* Separate a string using a delimiter that is not a space */
2730 static unsigned int separate_string_char_delim(char *buf
, char delim
, char **array
, unsigned int arraylen
)
2732 enum tokenizer_state
{
2737 unsigned int count
= 0;
2739 int inside_quotes
= 0;
2742 while (*ptr
&& count
< arraylen
) {
2745 array
[count
++] = ptr
;
2750 /* escaped characters are copied verbatim to the destination string */
2751 if (*ptr
== ESCAPE_META
) {
2753 } else if (*ptr
== '\'' && (inside_quotes
|| strchr(ptr
+1, '\''))) {
2754 inside_quotes
= (1 - inside_quotes
);
2755 } else if (*ptr
== delim
&& !inside_quotes
) {
2763 /* strip quotes, escaped chars and leading / trailing spaces */
2765 for (i
= 0; i
< count
; ++i
) {
2766 array
[i
] = cleanup_separated_string(array
[i
], delim
);
2772 /* Separate a string using a delimiter that is a space */
2773 static unsigned int separate_string_blank_delim(char *buf
, char **array
, unsigned int arraylen
)
2775 enum tokenizer_state
{
2782 unsigned int count
= 0;
2784 int inside_quotes
= 0;
2787 while (*ptr
&& count
< arraylen
) {
2790 array
[count
++] = ptr
;
2791 state
= SKIP_INITIAL_SPACE
;
2794 case SKIP_INITIAL_SPACE
:
2803 if (*ptr
== ESCAPE_META
) {
2805 } else if (*ptr
== '\'') {
2806 inside_quotes
= (1 - inside_quotes
);
2807 } else if (*ptr
== ' ' && !inside_quotes
) {
2809 state
= SKIP_ENDING_SPACE
;
2814 case SKIP_ENDING_SPACE
:
2823 /* strip quotes, escaped chars and leading / trailing spaces */
2825 for (i
= 0; i
< count
; ++i
) {
2826 array
[i
] = cleanup_separated_string(array
[i
], 0);
2832 SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf
, char delim
, char **array
, unsigned int arraylen
)
2834 if (!buf
|| !array
|| !arraylen
) {
2839 if (*buf
== '^' && *(buf
+1) == '^') {
2849 memset(array
, 0, arraylen
* sizeof(*array
));
2851 return (delim
== ' ' ? separate_string_blank_delim(buf
, array
, arraylen
) : separate_string_char_delim(buf
, delim
, array
, arraylen
));
2854 SWITCH_DECLARE(const char *) switch_cut_path(const char *in
)
2856 const char *p
, *ret
= in
;
2857 const char delims
[] = "/\\";
2861 for (i
= delims
; *i
; i
++) {
2863 while ((p
= strchr(p
, *i
)) != 0) {
2873 SWITCH_DECLARE(switch_status_t
) switch_string_match(const char *string
, size_t string_len
, const char *search
, size_t search_len
)
2877 for (i
= 0; (i
< search_len
) && (i
< string_len
); i
++) {
2878 if (string
[i
] != search
[i
]) {
2879 return SWITCH_STATUS_FALSE
;
2883 if (i
== search_len
) {
2884 return SWITCH_STATUS_SUCCESS
;
2887 return SWITCH_STATUS_FALSE
;
2890 SWITCH_DECLARE(char *) switch_string_replace(const char *string
, const char *search
, const char *replace
)
2892 size_t string_len
= strlen(string
);
2893 size_t search_len
= strlen(search
);
2894 size_t replace_len
= strlen(replace
);
2896 size_t dest_len
= 0;
2899 dest
= (char *) malloc(sizeof(char));
2900 switch_assert(dest
);
2902 for (i
= 0; i
< string_len
; i
++) {
2903 if (switch_string_match(string
+ i
, string_len
- i
, search
, search_len
) == SWITCH_STATUS_SUCCESS
) {
2904 for (n
= 0; n
< replace_len
; n
++) {
2905 dest
[dest_len
] = replace
[n
];
2907 tmp
= (char *) realloc(dest
, sizeof(char) * (dest_len
+ 1));
2911 i
+= search_len
- 1;
2913 dest
[dest_len
] = string
[i
];
2915 tmp
= (char *) realloc(dest
, sizeof(char) * (dest_len
+ 1));
2925 SWITCH_DECLARE(char *) switch_util_quote_shell_arg(const char *string
)
2927 return switch_util_quote_shell_arg_pool(string
, NULL
);
2930 SWITCH_DECLARE(char *) switch_util_quote_shell_arg_pool(const char *string
, switch_memory_pool_t
*pool
)
2932 size_t string_len
= strlen(string
);
2935 size_t dest_len
= 0;
2938 /* first pass through, figure out how large to make the allocation */
2939 dest_len
= strlen(string
) + 1; /* string + null */
2940 dest_len
+= 1; /* opening quote */
2941 for (i
= 0; i
< string_len
; i
++) {
2942 switch (string
[i
]) {
2945 /* We replace ' by sq backslace sq sq, so need 3 additional bytes */
2951 dest_len
+= 1; /* closing quote */
2953 /* if we're given a pool, allocate from it, otherwise use malloc */
2955 dest
= switch_core_alloc(pool
, sizeof(char) * dest_len
);
2957 dest
= (char *) malloc(sizeof(char) * dest_len
);
2959 switch_assert(dest
);
2967 for (i
= 0; i
< string_len
; i
++) {
2968 switch (string
[i
]) {
2976 /* We replace ' by sq backslash sq sq */
2984 dest
[n
++] = string
[i
];
2994 switch_assert(n
== dest_len
);
3002 SWITCH_DECLARE(int) switch_wait_sock(switch_os_socket_t sock
, uint32_t ms
, switch_poll_t flags
)
3004 struct pollfd pfds
[2] = { { 0 } };
3007 if (sock
== SWITCH_SOCK_INVALID
) {
3008 return SWITCH_SOCK_INVALID
;
3014 if ((flags
& SWITCH_POLL_READ
)) {
3015 pfds
[0].events
|= POLLIN
;
3018 if ((flags
& SWITCH_POLL_WRITE
)) {
3019 pfds
[0].events
|= POLLOUT
;
3022 if ((flags
& SWITCH_POLL_ERROR
)) {
3023 pfds
[0].events
|= POLLERR
;
3026 if ((flags
& SWITCH_POLL_HUP
)) {
3027 pfds
[0].events
|= POLLHUP
;
3030 if ((flags
& SWITCH_POLL_RDNORM
)) {
3031 pfds
[0].events
|= POLLRDNORM
;
3034 if ((flags
& SWITCH_POLL_RDBAND
)) {
3035 pfds
[0].events
|= POLLRDBAND
;
3038 if ((flags
& SWITCH_POLL_PRI
)) {
3039 pfds
[0].events
|= POLLPRI
;
3042 s
= poll(pfds
, 1, ms
);
3045 if (switch_errno_is_break(switch_errno())) {
3053 if ((pfds
[0].revents
& POLLIN
)) {
3054 r
|= SWITCH_POLL_READ
;
3056 if ((pfds
[0].revents
& POLLOUT
)) {
3057 r
|= SWITCH_POLL_WRITE
;
3059 if ((pfds
[0].revents
& POLLERR
)) {
3060 r
|= SWITCH_POLL_ERROR
;
3062 if ((pfds
[0].revents
& POLLHUP
)) {
3063 r
|= SWITCH_POLL_HUP
;
3065 if ((pfds
[0].revents
& POLLRDNORM
)) {
3066 r
|= SWITCH_POLL_RDNORM
;
3068 if ((pfds
[0].revents
& POLLRDBAND
)) {
3069 r
|= SWITCH_POLL_RDBAND
;
3071 if ((pfds
[0].revents
& POLLPRI
)) {
3072 r
|= SWITCH_POLL_PRI
;
3074 if ((pfds
[0].revents
& POLLNVAL
)) {
3075 r
|= SWITCH_POLL_INVALID
;
3083 SWITCH_DECLARE(int) switch_wait_socklist(switch_waitlist_t
*waitlist
, uint32_t len
, uint32_t ms
)
3085 struct pollfd
*pfds
;
3086 int s
= 0, r
= 0, i
;
3088 pfds
= calloc(len
, sizeof(struct pollfd
));
3089 switch_assert(pfds
);
3091 for (i
= 0; i
< len
; i
++) {
3092 if (waitlist
[i
].sock
== SWITCH_SOCK_INVALID
) {
3096 pfds
[i
].fd
= waitlist
[i
].sock
;
3098 if ((waitlist
[i
].events
& SWITCH_POLL_READ
)) {
3099 pfds
[i
].events
|= POLLIN
;
3102 if ((waitlist
[i
].events
& SWITCH_POLL_WRITE
)) {
3103 pfds
[i
].events
|= POLLOUT
;
3106 if ((waitlist
[i
].events
& SWITCH_POLL_ERROR
)) {
3107 pfds
[i
].events
|= POLLERR
;
3110 if ((waitlist
[i
].events
& SWITCH_POLL_HUP
)) {
3111 pfds
[i
].events
|= POLLHUP
;
3114 if ((waitlist
[i
].events
& SWITCH_POLL_RDNORM
)) {
3115 pfds
[i
].events
|= POLLRDNORM
;
3118 if ((waitlist
[i
].events
& SWITCH_POLL_RDBAND
)) {
3119 pfds
[i
].events
|= POLLRDBAND
;
3122 if ((waitlist
[i
].events
& SWITCH_POLL_PRI
)) {
3123 pfds
[i
].events
|= POLLPRI
;
3127 s
= poll(pfds
, len
, ms
);
3130 if (switch_errno_is_break(switch_errno())) {
3138 for (i
= 0; i
< len
; i
++) {
3139 if ((pfds
[i
].revents
& POLLIN
)) {
3140 r
|= SWITCH_POLL_READ
;
3141 waitlist
[i
].revents
|= SWITCH_POLL_READ
;
3143 if ((pfds
[i
].revents
& POLLOUT
)) {
3144 r
|= SWITCH_POLL_WRITE
;
3145 waitlist
[i
].revents
|= SWITCH_POLL_WRITE
;
3147 if ((pfds
[i
].revents
& POLLERR
)) {
3148 r
|= SWITCH_POLL_ERROR
;
3149 waitlist
[i
].revents
|= SWITCH_POLL_ERROR
;
3151 if ((pfds
[i
].revents
& POLLHUP
)) {
3152 r
|= SWITCH_POLL_HUP
;
3153 waitlist
[i
].revents
|= SWITCH_POLL_HUP
;
3155 if ((pfds
[i
].revents
& POLLRDNORM
)) {
3156 r
|= SWITCH_POLL_RDNORM
;
3157 waitlist
[i
].revents
|= SWITCH_POLL_RDNORM
;
3159 if ((pfds
[i
].revents
& POLLRDBAND
)) {
3160 r
|= SWITCH_POLL_RDBAND
;
3161 waitlist
[i
].revents
|= SWITCH_POLL_RDBAND
;
3163 if ((pfds
[i
].revents
& POLLPRI
)) {
3164 r
|= SWITCH_POLL_PRI
;
3165 waitlist
[i
].revents
|= SWITCH_POLL_PRI
;
3167 if ((pfds
[i
].revents
& POLLNVAL
)) {
3168 r
|= SWITCH_POLL_INVALID
;
3169 waitlist
[i
].revents
|= SWITCH_POLL_INVALID
;
3181 /* use select instead of poll */
3182 SWITCH_DECLARE(int) switch_wait_sock(switch_os_socket_t sock
, uint32_t ms
, switch_poll_t flags
)
3190 if (sock
== SWITCH_SOCK_INVALID
) {
3191 return SWITCH_SOCK_INVALID
;
3194 rfds
= malloc(sizeof(fd_set
));
3195 wfds
= malloc(sizeof(fd_set
));
3196 efds
= malloc(sizeof(fd_set
));
3203 /* Wouldn't you rather know?? */
3204 assert(sock
<= FD_SETSIZE
);
3207 if ((flags
& SWITCH_POLL_READ
)) {
3210 #pragma warning( push )
3211 #pragma warning( disable : 4127 )
3213 #pragma warning( pop )
3219 if ((flags
& SWITCH_POLL_WRITE
)) {
3222 #pragma warning( push )
3223 #pragma warning( disable : 4127 )
3225 #pragma warning( pop )
3231 if ((flags
& SWITCH_POLL_ERROR
)) {
3234 #pragma warning( push )
3235 #pragma warning( disable : 4127 )
3237 #pragma warning( pop )
3243 tv
.tv_sec
= ms
/ 1000;
3244 tv
.tv_usec
= (ms
% 1000) * 1000;
3246 s
= select(sock
+ 1, (flags
& SWITCH_POLL_READ
) ? rfds
: NULL
, (flags
& SWITCH_POLL_WRITE
) ? wfds
: NULL
, (flags
& SWITCH_POLL_ERROR
) ? efds
: NULL
, &tv
);
3249 if (switch_errno_is_break(switch_errno())) {
3257 if ((flags
& SWITCH_POLL_READ
) && FD_ISSET(sock
, rfds
)) {
3258 r
|= SWITCH_POLL_READ
;
3261 if ((flags
& SWITCH_POLL_WRITE
) && FD_ISSET(sock
, wfds
)) {
3262 r
|= SWITCH_POLL_WRITE
;
3265 if ((flags
& SWITCH_POLL_ERROR
) && FD_ISSET(sock
, efds
)) {
3266 r
|= SWITCH_POLL_ERROR
;
3278 SWITCH_DECLARE(int) switch_wait_socklist(switch_waitlist_t
*waitlist
, uint32_t len
, uint32_t ms
)
3286 switch_os_socket_t max_fd
= 0;
3289 rfds
= malloc(sizeof(fd_set
));
3290 wfds
= malloc(sizeof(fd_set
));
3291 efds
= malloc(sizeof(fd_set
));
3297 for (i
= 0; i
< len
; i
++) {
3298 if (waitlist
[i
].sock
== SWITCH_SOCK_INVALID
) {
3302 if (waitlist
[i
].sock
> max_fd
) {
3303 max_fd
= waitlist
[i
].sock
;
3307 /* Wouldn't you rather know?? */
3308 assert(waitlist
[i
].sock
<= FD_SETSIZE
);
3310 flags
|= waitlist
[i
].events
;
3312 if ((waitlist
[i
].events
& SWITCH_POLL_READ
)) {
3315 #pragma warning( push )
3316 #pragma warning( disable : 4127 )
3317 FD_SET(waitlist
[i
].sock
, rfds
);
3318 #pragma warning( pop )
3320 FD_SET(waitlist
[i
].sock
, rfds
);
3324 if ((waitlist
[i
].events
& SWITCH_POLL_WRITE
)) {
3327 #pragma warning( push )
3328 #pragma warning( disable : 4127 )
3329 FD_SET(waitlist
[i
].sock
, wfds
);
3330 #pragma warning( pop )
3332 FD_SET(waitlist
[i
].sock
, wfds
);
3336 if ((waitlist
[i
].events
& SWITCH_POLL_ERROR
)) {
3339 #pragma warning( push )
3340 #pragma warning( disable : 4127 )
3341 FD_SET(waitlist
[i
].sock
, efds
);
3342 #pragma warning( pop )
3344 FD_SET(waitlist
[i
].sock
, efds
);
3349 tv
.tv_sec
= ms
/ 1000;
3350 tv
.tv_usec
= (ms
% 1000) * 1000;
3352 s
= select(max_fd
+ 1, (flags
& SWITCH_POLL_READ
) ? rfds
: NULL
, (flags
& SWITCH_POLL_WRITE
) ? wfds
: NULL
, (flags
& SWITCH_POLL_ERROR
) ? efds
: NULL
, &tv
);
3355 if (switch_errno_is_break(switch_errno())) {
3363 for (i
= 0; i
< len
; i
++) {
3364 if ((waitlist
[i
].events
& SWITCH_POLL_READ
) && FD_ISSET(waitlist
[i
].sock
, rfds
)) {
3365 r
|= SWITCH_POLL_READ
;
3366 waitlist
[i
].revents
|= SWITCH_POLL_READ
;
3369 if ((waitlist
[i
].events
& SWITCH_POLL_WRITE
) && FD_ISSET(waitlist
[i
].sock
, wfds
)) {
3370 r
|= SWITCH_POLL_WRITE
;
3371 waitlist
[i
].revents
|= SWITCH_POLL_WRITE
;
3374 if ((waitlist
[i
].events
& SWITCH_POLL_ERROR
) && FD_ISSET(waitlist
[i
].sock
, efds
)) {
3375 r
|= SWITCH_POLL_ERROR
;
3376 waitlist
[i
].revents
|= SWITCH_POLL_ERROR
;
3390 SWITCH_DECLARE(int) switch_socket_waitfor(switch_pollfd_t
*poll
, int ms
)
3394 switch_poll(poll
, 1, &nsds
, ms
);
3399 SWITCH_DECLARE(char *) switch_core_session_url_encode(switch_core_session_t
*session
, const char *url
)
3401 return switch_core_url_encode_opt(switch_core_session_get_pool(session
), url
, SWITCH_FALSE
);
3404 SWITCH_DECLARE(char *) switch_core_session_url_encode_opt(switch_core_session_t
*session
, const char *url
, switch_bool_t double_encode
)
3406 return switch_core_url_encode_opt(switch_core_session_get_pool(session
), url
, double_encode
);
3409 SWITCH_DECLARE(char *) switch_core_url_encode(switch_memory_pool_t
*pool
, const char *url
)
3411 return switch_core_url_encode_opt(pool
, url
, SWITCH_FALSE
);
3414 SWITCH_DECLARE(char *) switch_core_url_encode_opt(switch_memory_pool_t
*pool
, const char *url
, switch_bool_t double_encode
)
3416 const char hex
[] = "0123456789ABCDEF";
3417 switch_size_t len
= 0;
3418 switch_size_t slen
= 0;
3421 if (!url
) return NULL
;
3422 if (!pool
) return NULL
;
3426 for (p
= url
; *p
; p
++) {
3432 if (!double_encode
&& *p
== '%' && e
-p
> 1) {
3433 if (strchr(hex
, *(p
+1)) && strchr(hex
, *(p
+2))) {
3438 if (!ok
&& (*p
< ' ' || *p
> '~' || strchr(SWITCH_URL_UNSAFE
, *p
))) {
3444 len
++; /* NULL Terminatior */
3447 return switch_core_strdup(pool
, url
);
3449 return switch_url_encode_opt(url
, switch_core_alloc(pool
, sizeof(char) * len
), len
, double_encode
);
3453 SWITCH_DECLARE(char *) switch_url_encode_opt(const char *url
, char *buf
, size_t len
, switch_bool_t double_encode
)
3455 const char *p
, *e
= end_of_p(url
);
3457 const char hex
[] = "0123456789ABCDEF";
3469 for (p
= url
; *p
; p
++) {
3476 if (!double_encode
&& *p
== '%' && e
-p
> 1) {
3477 if (strchr(hex
, *(p
+1)) && strchr(hex
, *(p
+2))) {
3482 if (!ok
&& (*p
< ' ' || *p
> '~' || strchr(SWITCH_URL_UNSAFE
, *p
))) {
3483 if ((x
+ 3) > len
) {
3487 buf
[x
++] = hex
[(*p
>> 4) & 0x0f];
3488 buf
[x
++] = hex
[*p
& 0x0f];
3498 SWITCH_DECLARE(char *) switch_url_encode(const char *url
, char *buf
, size_t len
)
3500 return switch_url_encode_opt(url
, buf
, len
, SWITCH_FALSE
);
3503 SWITCH_DECLARE(char *) switch_url_decode(char *s
)
3508 if (zstr(s
) || !strchr(s
, '%')) {
3512 for (o
= s
; *s
; s
++, o
++) {
3513 if (*s
== '%' && strlen(s
) > 2 && sscanf(s
+ 1, "%2x", &tmp
) == 1) {
3524 SWITCH_DECLARE(void) switch_split_time(const char *exp
, int *hour
, int *min
, int *sec
)
3526 char *dup
= strdup(exp
);
3534 if ((smin
=strchr(dup
, ':'))) {
3536 if ((ssec
=strchr(smin
, ':'))) {
3542 *hour
= atol(shour
);
3552 switch_safe_free(dup
);
3557 SWITCH_DECLARE(void) switch_split_date(const char *exp
, int *year
, int *month
, int *day
)
3559 char *dup
= strdup(exp
);
3561 char *smonth
= NULL
;
3567 if ((smonth
=strchr(dup
, '-'))) {
3569 if ((sday
=strchr(smonth
, '-'))) {
3572 *year
= atol(syear
);
3575 *month
= atol(smonth
);
3582 switch_safe_free(dup
);
3587 /* Ex exp value "2009-10-10 14:33:22~2009-11-10 17:32:31" */
3588 SWITCH_DECLARE(int) switch_fulldate_cmp(const char *exp
, switch_time_t
*ts
)
3590 char *dup
= strdup(exp
);
3595 switch_time_t tsStart
= 0;
3596 switch_time_t tsEnd
= 0;
3602 if ((p
= strchr(cur
, ','))) {
3608 if ((sEnd
= strchr(cur
, '~'))) {
3611 tsStart
= switch_str_time(sStart
);
3612 tsEnd
= switch_str_time(sEnd
);
3615 if (tsStart
== 0 || tsEnd
== 0) {
3616 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Parse error for date time range (%s~%s)\n", sStart
, sEnd
);
3620 if (tsStart
<= *ts
&& tsEnd
> *ts
) {
3627 if ((p
= strchr(p
, ','))) {
3633 switch_safe_free(dup
);
3638 /* Written by Marc Espie, public domain */
3639 #define SWITCH_CTYPE_NUM_CHARS 256
3641 const short _switch_C_toupper_
[1 + SWITCH_CTYPE_NUM_CHARS
] = {
3643 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
3644 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
3645 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3646 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3647 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3648 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3649 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3650 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3651 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
3652 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
3653 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
3654 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3655 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
3656 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
3657 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
3658 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3659 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3660 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3661 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3662 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3663 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3664 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3665 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3666 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3667 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3668 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3669 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3670 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3671 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3672 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3673 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3674 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3677 const short *_switch_toupper_tab_
= _switch_C_toupper_
;
3679 SWITCH_DECLARE(int) old_switch_toupper(int c
)
3681 if ((unsigned int) c
> 255)
3685 return ((_switch_toupper_tab_
+ 1)[c
]);
3688 const short _switch_C_tolower_
[1 + SWITCH_CTYPE_NUM_CHARS
] = {
3690 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
3691 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
3692 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3693 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3694 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3695 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3696 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3697 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3698 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3699 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3700 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3701 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3702 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3703 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
3704 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
3705 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3706 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3707 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3708 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3709 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3710 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3711 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3712 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3713 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3714 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3715 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3716 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3717 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3718 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3719 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3720 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3721 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3724 const short *_switch_tolower_tab_
= _switch_C_tolower_
;
3726 SWITCH_DECLARE(int) old_switch_tolower(int c
)
3728 if ((unsigned int) c
> 255)
3732 return ((_switch_tolower_tab_
+ 1)[c
]);
3736 * Copyright (c) 1989 The Regents of the University of California.
3737 * All rights reserved.
3738 * (c) UNIX System Laboratories, Inc.
3739 * All or some portions of this file are derived from material licensed
3740 * to the University of California by American Telephone and Telegraph
3741 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
3742 * the permission of UNIX System Laboratories, Inc.
3744 * Redistribution and use in source and binary forms, with or without
3745 * modification, are permitted provided that the following conditions
3747 * 1. Redistributions of source code must retain the above copyright
3748 * notice, this list of conditions and the following disclaimer.
3749 * 2. Redistributions in binary form must reproduce the above copyright
3750 * notice, this list of conditions and the following disclaimer in the
3751 * documentation and/or other materials provided with the distribution.
3752 * 3. Neither the name of the University nor the names of its contributors
3753 * may be used to endorse or promote products derived from this software
3754 * without specific prior written permission.
3756 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3757 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3758 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3759 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3760 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3761 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3762 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3763 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3764 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3765 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3787 const int _switch_C_ctype_
[1 + SWITCH_CTYPE_NUM_CHARS
] = {
3789 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
,
3790 _C
, _C
| _S
, _C
| _S
, _C
| _S
, _C
| _S
, _C
| _S
, _C
, _C
,
3791 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
,
3792 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
,
3793 _S
| _B
, _P
, _P
, _P
, _P
, _P
, _P
, _P
,
3794 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
,
3795 _N
, _N
, _N
, _N
, _N
, _N
, _N
, _N
,
3796 _N
, _N
, _P
, _P
, _P
, _P
, _P
, _P
,
3797 _P
, _U
| _X
, _U
| _X
, _U
| _X
, _U
| _X
, _U
| _X
, _U
| _X
, _U
,
3798 _U
, _U
, _U
, _U
, _U
, _U
, _U
, _U
,
3799 _U
, _U
, _U
, _U
, _U
, _U
, _U
, _U
,
3800 _U
, _U
, _U
, _P
, _P
, _P
, _P
, _P
,
3801 _P
, _L
| _X
, _L
| _X
, _L
| _X
, _L
| _X
, _L
| _X
, _L
| _X
, _L
,
3802 _L
, _L
, _L
, _L
, _L
, _L
, _L
, _L
,
3803 _L
, _L
, _L
, _L
, _L
, _L
, _L
, _L
,
3804 /* determine printability based on the IS0 8859 8-bit standard */
3805 _L
, _L
, _L
, _P
, _P
, _P
, _P
, _C
,
3807 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
, /* 80 */
3808 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
, /* 88 */
3809 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
, /* 90 */
3810 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
, /* 98 */
3811 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* A0 */
3812 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* A8 */
3813 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* B0 */
3814 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* B8 */
3815 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* C0 */
3816 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* C8 */
3817 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* D0 */
3818 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* D8 */
3819 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* E0 */
3820 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* E8 */
3821 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* F0 */
3822 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
/* F8 */
3825 const int *_switch_ctype_
= _switch_C_ctype_
;
3827 SWITCH_DECLARE(int) switch_isalnum(int c
)
3829 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & (_U
| _L
| _N
)));
3832 SWITCH_DECLARE(int) switch_isalpha(int c
)
3834 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & (_U
| _L
)));
3837 SWITCH_DECLARE(int) switch_iscntrl(int c
)
3839 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _C
));
3842 SWITCH_DECLARE(int) switch_isdigit(int c
)
3844 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _N
));
3847 SWITCH_DECLARE(int) switch_isgraph(int c
)
3849 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & (_P
| _U
| _L
| _N
)));
3852 SWITCH_DECLARE(int) switch_islower(int c
)
3854 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _L
));
3857 SWITCH_DECLARE(int) switch_isprint(int c
)
3859 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & (_P
| _U
| _L
| _N
| _B
)));
3862 SWITCH_DECLARE(int) switch_ispunct(int c
)
3864 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _P
));
3867 SWITCH_DECLARE(int) switch_isspace(int c
)
3869 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _S
));
3872 SWITCH_DECLARE(int) switch_isupper(int c
)
3874 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _U
));
3877 SWITCH_DECLARE(int) switch_isxdigit(int c
)
3879 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & (_N
| _X
)));
3881 static const char *DOW
[] = {
3891 SWITCH_DECLARE(const char *) switch_dow_int2str(int val
) {
3892 if (val
>= switch_arraylen(DOW
)) {
3893 val
= val
% switch_arraylen(DOW
);
3898 SWITCH_DECLARE(int) switch_dow_str2int(const char *exp
) {
3902 for (x
= 0; x
< switch_arraylen(DOW
); x
++) {
3903 if (!strncasecmp(DOW
[x
], exp
, 3)) {
3925 static inline dow_t
_dow_read_token(const char **s
)
3932 } else if (**s
== ',') {
3935 } else if (**s
>= '1' && **s
<= '7') {
3936 dow_t r
= **s
- '0';
3939 } else if ((i
= switch_dow_str2int(*s
)) && i
!= -1) {
3949 SWITCH_DECLARE(switch_bool_t
) switch_dow_cmp(const char *exp
, int val
)
3951 dow_t cur
, prev
= DOW_EOF
, range_start
= DOW_EOF
;
3952 const char *p
= exp
;
3954 while ((cur
= _dow_read_token(&p
)) != DOW_EOF
) {
3955 if (cur
== DOW_COMA
) {
3958 } else if (cur
== DOW_HYPHEN
) {
3959 /* Save the previous token and move to the next one */
3961 } else if (cur
== DOW_ERR
) {
3962 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Parse error for [%s] at position %ld (%.6s)\n", exp
, (long) (p
- exp
), p
);
3965 /* Valid day found */
3966 if (range_start
!= DOW_EOF
) { /* Evaluating a range */
3967 if (range_start
<= cur
? (val
>= range_start
&& val
<= cur
) : (val
>= range_start
|| val
<= cur
)) {
3970 range_start
= DOW_EOF
;
3971 } else if (val
== cur
) {
3979 return SWITCH_FALSE
;
3982 SWITCH_DECLARE(int) switch_number_cmp(const char *exp
, int val
)
3984 // Expression exp must be a comma separated list of numbers or ranges.
3985 // To match numbers not in range 9-17, enter the reversed range 18-8.
3987 int a
= strtol(exp
, (char **)&exp
, 10);
3992 int b
= strtol(++exp
, (char **)&exp
, 10);
3993 if (a
<= b
? (val
>= a
&& val
<=b
) : (val
>= a
|| val
<= b
))
4001 SWITCH_DECLARE(int) switch_tod_cmp(const char *exp
, int val
)
4003 char *dup
= strdup(exp
);
4012 int range_start
, range_end
;
4017 if ((p
= strchr(cur
, ','))) {
4023 if ((minm
=strchr(cur
, ':'))) {
4025 if ((maxh
=strchr(minm
, '-'))) {
4026 if ((maxm
=strchr(maxh
, ':'))) {
4029 /* Check if min/max seconds are present */
4030 if ((mins
=strchr(minm
, ':'))) {
4035 if ((maxs
=strchr(maxm
, ':'))) {
4041 range_start
= (atol(minh
) * 60 * 60) + (atol(minm
) * 60) + atol(mins
);
4042 range_end
= (atol(maxh
) * 60 * 60) + (atol(maxm
) * 60) + atol(maxs
);
4043 if (range_start
<= range_end
? (val
>= range_start
&& val
<= range_end
) : (val
>= range_start
|| val
<= range_end
)) {
4044 switch_safe_free(dup
);
4053 if ((p
= strchr(p
, ','))) {
4060 switch_safe_free(dup
);
4065 SWITCH_DECLARE(int) switch_split_user_domain(char *in
, char **user
, char **domain
)
4067 char *p
= NULL
, *h
= NULL
, *u
= NULL
;
4071 /* Remove URL scheme */
4072 if (!strncasecmp(in
, "sip:", 4)) in
+= 4;
4073 else if (!strncasecmp(in
, "sips:", 5)) in
+= 5;
4075 /* Isolate the host part from the user part */
4076 if ((h
= in
, p
= strchr(h
, '@'))) *p
= '\0', u
= in
, h
= p
+1;
4078 /* Clean out the host part of any suffix */
4079 for (p
= h
; *p
; p
++)
4080 if (*p
== ':' || *p
== ';' || *p
== ' ') {
4084 if (user
) *user
= u
;
4085 if (domain
) *domain
= h
;
4090 SWITCH_DECLARE(char *) switch_uuid_str(char *buf
, switch_size_t len
)
4094 if (len
< (SWITCH_UUID_FORMATTED_LENGTH
+ 1)) {
4095 switch_snprintf(buf
, len
, "INVALID");
4097 switch_uuid_get(&uuid
);
4098 switch_uuid_format(buf
, &uuid
);
4105 SWITCH_DECLARE(char *) switch_format_number(const char *num
)
4109 const char *p
= num
;
4123 if (!switch_is_number(p
)) {
4129 /* region 1, TBD add more....*/
4130 if (len
== 11 && p
[0] == '1') {
4131 r
= switch_mprintf("%c (%c%c%c) %c%c%c-%c%c%c%c", p
[0],p
[1],p
[2],p
[3],p
[4],p
[5],p
[6],p
[7],p
[8],p
[9],p
[10]);
4132 } else if (len
== 10) {
4133 r
= switch_mprintf("1 (%c%c%c) %c%c%c-%c%c%c%c", p
[0],p
[1],p
[2],p
[3],p
[4],p
[5],p
[6],p
[7],p
[8],p
[9]);
4142 SWITCH_DECLARE(unsigned int) switch_atoui(const char *nptr
)
4144 int tmp
= atoi(nptr
);
4145 if (tmp
< 0) return 0;
4146 else return (unsigned int) tmp
;
4149 SWITCH_DECLARE(unsigned long) switch_atoul(const char *nptr
)
4151 long tmp
= atol(nptr
);
4152 if (tmp
< 0) return 0;
4153 else return (unsigned long) tmp
;
4157 SWITCH_DECLARE(char *) switch_strerror_r(int errnum
, char *buf
, switch_size_t buflen
)
4159 #ifdef HAVE_STRERROR_R
4160 #ifdef STRERROR_R_CHAR_P
4161 /* GNU variant returning char *, avoids warn-unused-result error */
4162 return strerror_r(errnum
, buf
, buflen
);
4165 * XSI variant returning int, with GNU compatible error string,
4166 * if no message could be found
4168 if (strerror_r(errnum
, buf
, buflen
)) {
4169 switch_snprintf(buf
, buflen
, "Unknown error %d", errnum
);
4172 #endif /* STRERROR_R_CHAR_P */
4173 #elif defined(WIN32)
4175 if (strerror_s(buf
, buflen
, errnum
)) {
4176 switch_snprintf(buf
, buflen
, "Unknown error %d", errnum
);
4180 /* Fallback, copy string into private buffer */
4181 switch_copy_string(buf
, strerror(errnum
), buflen
);
4186 SWITCH_DECLARE(void) switch_http_parse_qs(switch_http_request_t
*request
, char *qs
)
4195 } else { /*parse our own qs, dup to avoid modify the original string */
4196 dup
= q
= strdup(request
->qs
);
4205 if ((next
= strchr(next
, '&'))) {
4209 for (p
= q
; p
&& *p
; p
++) {
4210 if (*p
== '+') *p
= ' ';
4213 switch_url_decode(q
);
4216 if ((val
= strchr(name
, '='))) {
4218 switch_event_add_header_string(request
->headers
, SWITCH_STACK_BOTTOM
, name
, val
);
4223 switch_safe_free(dup
);
4226 /* clean the uri to protect us from vulnerability attack */
4227 switch_status_t
clean_uri(char *uri
)
4231 int last
, i
, len
, uri_len
= 0;
4233 argc
= switch_separate_string(uri
, '/', argv
, sizeof(argv
) / sizeof(argv
[0]));
4235 if (argc
== sizeof(argv
)) { /* too deep */
4236 return SWITCH_STATUS_FALSE
;
4240 for(i
= 1; i
< argc
; i
++) {
4241 if (*argv
[i
] == '\0' || !strcmp(argv
[i
], ".")) {
4242 /* ignore //// or /././././ */
4243 } else if (!strcmp(argv
[i
], "..")) {
4244 /* got /../, go up one level */
4245 if (last
> 1) last
--;
4247 argv
[last
++] = argv
[i
];
4251 for(i
= 1; i
< last
; i
++) {
4252 len
= strlen(argv
[i
]);
4253 sprintf(uri
+ uri_len
, "/%s", argv
[i
]);
4254 uri_len
+= (len
+ 1);
4257 return SWITCH_STATUS_SUCCESS
;
4260 SWITCH_DECLARE(switch_status_t
) switch_http_parse_header(char *buffer
, uint32_t datalen
, switch_http_request_t
*request
)
4262 switch_status_t status
= SWITCH_STATUS_FALSE
;
4267 char *headers
[64] = { 0 };
4269 char *argv
[2] = { 0 };
4272 if (datalen
< 16) return status
; /* minimum GET / HTTP/1.1\r\n */
4274 while(i
--) { // sanity check
4275 if (*p
++ == ' ') break;
4278 if (i
== 0) return status
;
4280 if ((body
= strstr(buffer
, "\r\n\r\n"))) {
4283 } else if (( body
= strstr(buffer
, "\n\n"))) {
4290 request
->_buffer
= strdup(buffer
);
4291 switch_assert(request
->_buffer
);
4292 request
->method
= request
->_buffer
;
4293 request
->bytes_buffered
= datalen
;
4294 request
->bytes_header
= body
- buffer
;
4295 request
->bytes_read
= body
- buffer
;
4297 p
= strchr(request
->method
, ' ');
4303 if (*p
!= '/') goto err
; /* must start from '/' */
4306 p
= strchr(request
->uri
, ' ');
4313 p
= strchr(request
->uri
, '?');
4320 if (clean_uri((char *)request
->uri
) != SWITCH_STATUS_SUCCESS
) {
4324 if (!strncmp(http
, "HTTP/1.1", 8)) {
4325 request
->keepalive
= SWITCH_TRUE
;
4326 } else if (strncmp(http
, "HTTP/1.0", 8)) {
4330 if (!request
->headers
) {
4331 if (switch_event_create(&request
->headers
, SWITCH_EVENT_CHANNEL_DATA
) != SWITCH_STATUS_SUCCESS
) {
4334 request
->_destroy_headers
= SWITCH_TRUE
;
4337 p
= strchr(http
, '\n');
4340 *p
++ = '\0'; // now the first header
4345 header_count
= switch_separate_string(p
, '\n', headers
, sizeof(headers
)/ sizeof(headers
[0]));
4347 if (header_count
< 1) goto err
;
4349 for (i
= 0; i
< header_count
; i
++) {
4350 char *header
, *value
;
4353 argc
= switch_separate_string(headers
[i
], ':', argv
, 2);
4355 if (argc
!= 2) goto err
;
4360 if (*value
== ' ') value
++;
4362 len
= strlen(value
);
4364 if (len
&& *(value
+ len
- 1) == '\r') *(value
+ len
- 1) = '\0';
4366 switch_event_add_header_string(request
->headers
, SWITCH_STACK_BOTTOM
, header
, value
);
4368 if (!strncasecmp(header
, "User-Agent", 10)) {
4369 request
->user_agent
= value
;
4370 } else if (!strncasecmp(header
, "Host", 4)) {
4371 request
->host
= value
;
4372 p
= strchr(value
, ':');
4377 if (*p
) request
->port
= (switch_port_t
)atoi(p
);
4379 } else if (!strncasecmp(header
, "Content-Type", 12)) {
4380 request
->content_type
= value
;
4381 } else if (!strncasecmp(header
, "Content-Length", 14)) {
4382 request
->content_length
= atoi(value
);
4383 } else if (!strncasecmp(header
, "Referer", 7)) {
4384 request
->referer
= value
;
4391 switch_http_parse_qs(request
, NULL
);
4394 return SWITCH_STATUS_SUCCESS
;
4397 switch_http_free_request(request
);
4401 SWITCH_DECLARE(void) switch_http_free_request(switch_http_request_t
*request
)
4403 if (request
->_buffer
) free(request
->_buffer
);
4404 if (request
->_destroy_headers
&& request
->headers
) {
4405 switch_event_destroy(&request
->headers
);
4409 /* for debugging only */
4410 SWITCH_DECLARE(void) switch_http_dump_request(switch_http_request_t
*request
)
4412 switch_assert(request
->method
);
4414 printf("method: %s\n", request
->method
);
4416 if (request
->uri
) printf("uri: %s\n", request
->uri
);
4417 if (request
->qs
) printf("qs: %s\n", request
->qs
);
4418 if (request
->host
) printf("host: %s\n", request
->host
);
4419 if (request
->port
) printf("port: %d\n", request
->port
);
4420 if (request
->from
) printf("from: %s\n", request
->from
);
4421 if (request
->user_agent
) printf("user_agent: %s\n", request
->user_agent
);
4422 if (request
->referer
) printf("referer: %s\n", request
->referer
);
4423 if (request
->user
) printf("user: %s\n", request
->user
);
4424 if (request
->keepalive
) printf("uri: %d\n", request
->keepalive
);
4425 if (request
->content_type
) printf("uri: %s\n", request
->content_type
);
4426 if (request
->content_length
) printf("uri: %" SWITCH_SIZE_T_FMT
"\n", request
->content_length
);
4429 switch_event_header_t
*header
= request
->headers
->headers
;
4431 printf("headers:\n-------------------------\n");
4434 printf("%s: %s\n", header
->name
, header
->value
);
4435 header
= header
->next
;
4440 SWITCH_DECLARE(void) switch_getcputime(switch_cputime
*t
)
4443 FILETIME ct
, et
, kt
, ut
; // Times are in 100-ns ticks (div 10000 to get ms)
4444 GetProcessTimes(GetCurrentProcess(), &ct
, &et
, &kt
, &ut
);
4445 t
->userms
= ((int64_t)ut
.dwLowDateTime
| ((int64_t)ut
.dwHighDateTime
<< 32)) / 10000;
4446 t
->kernelms
= ((int64_t)kt
.dwLowDateTime
| ((int64_t)kt
.dwHighDateTime
<< 32)) / 10000;
4447 #elif defined(HAVE_GETRUSAGE)
4449 getrusage(RUSAGE_SELF
, &r
);
4450 t
->userms
= r
.ru_utime
.tv_sec
* 1000 + r
.ru_utime
.tv_usec
/ 1000;
4451 t
->kernelms
= r
.ru_stime
.tv_sec
* 1000 + r
.ru_stime
.tv_usec
/ 1000;
4459 #ifdef SWITCH_HAVE_GUMBO
4460 static void process(GumboNode
*node
, switch_stream_handle_t
*stream
)
4462 if (node
->type
== GUMBO_NODE_TEXT
) {
4463 stream
->write_function(stream
, "%s", node
->v
.text
.text
);
4465 } else if (node
->type
== GUMBO_NODE_ELEMENT
&& node
->v
.element
.tag
!= GUMBO_TAG_SCRIPT
&& node
->v
.element
.tag
!= GUMBO_TAG_STYLE
) {
4466 GumboVector
*children
= &node
->v
.element
.children
;
4469 if (node
->v
.element
.tag
!= GUMBO_TAG_UNKNOWN
&& node
->v
.element
.tag
<= GUMBO_TAG_LAST
) {
4470 GumboAttribute
* attr
= NULL
;
4471 const char *aval
= NULL
;
4473 if (node
->v
.element
.tag
== GUMBO_TAG_SPAN
) {
4474 if ((attr
= gumbo_get_attribute(&node
->v
.element
.attributes
, "class"))) {
4479 if (aval
&& !strcasecmp(aval
, "Apple-converted-space")) {
4480 const char *txt
= ((GumboNode
*)children
->data
[0])->v
.text
.text
;
4483 for (x
= 0; txt
[x
]; x
++) {
4484 if (txt
[x
] == ' ') {
4489 for (x
= 0; x
< len
*2; x
++) {
4490 stream
->write_function(stream
, "%s", " ");
4493 for (i
= 0; i
< children
->length
; ++i
) {
4494 process((GumboNode
*) children
->data
[i
], stream
);
4498 if (node
->v
.element
.tag
== GUMBO_TAG_P
|| node
->v
.element
.tag
== GUMBO_TAG_BR
) {
4499 stream
->write_function(stream
, "%s", "\n");
4507 SWITCH_DECLARE(char *)switch_html_strip(const char *str
)
4509 char *p
, *html
= NULL
, *text
= NULL
;
4510 int x
= 0, got_ct
= 0;
4511 #ifdef SWITCH_HAVE_GUMBO
4512 GumboOutput
*output
;
4513 switch_stream_handle_t stream
;
4515 SWITCH_STANDARD_STREAM(stream
);
4518 for(p
= (char *)str
; p
&& *p
; p
++) {
4520 if (!strncasecmp(p
, "Content-Type:", 13)) {
4524 if (!got_ct
) continue;
4531 } else if (x
&& (*p
!= '\r')) {
4538 #ifdef SWITCH_HAVE_GUMBO
4539 if ((output
= gumbo_parse_with_options(&kGumboDefaultOptions
, html
, strlen(html
)))) {
4540 process(output
->root
, &stream
);
4541 gumbo_destroy_output(&kGumboDefaultOptions
, output
);
4544 text
= (char *)stream
.data
;
4546 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "Support for html parser is not compiled.\n");
4547 text
= switch_safe_strdup(html
);
4553 SWITCH_DECLARE(unsigned long) switch_getpid(void)
4556 pid_t pid
= getpid();
4558 int pid
= _getpid();
4561 return (unsigned long)pid
;
4564 SWITCH_DECLARE(switch_status_t
) switch_digest(const char *digest_name
, unsigned char **digest
, const void *input
, switch_size_t inputLen
, unsigned int *outputlen
)
4566 #if defined(HAVE_OPENSSL)
4571 switch_assert(digest
);
4574 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Message digest is not set\n");
4575 return SWITCH_STATUS_FALSE
;
4578 md
= EVP_get_digestbyname(digest_name
);
4581 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Unknown message digest %s\n", digest_name
);
4582 return SWITCH_STATUS_FALSE
;
4585 size
= EVP_MD_size(md
);
4586 if (!size
|| !(*digest
= malloc(size
))) {
4587 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Zero digest size or can't allocate memory to store results %s\n", digest_name
);
4588 return SWITCH_STATUS_FALSE
;
4591 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
4592 mdctx
= EVP_MD_CTX_new();
4594 mdctx
= EVP_MD_CTX_create();
4598 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "EVP_MD_CTX_new error\n");
4599 switch_safe_free(*digest
);
4600 return SWITCH_STATUS_FALSE
;
4603 EVP_MD_CTX_init(mdctx
);
4604 EVP_DigestInit_ex(mdctx
, md
, NULL
);
4605 EVP_DigestUpdate(mdctx
, input
, inputLen
);
4606 EVP_DigestFinal_ex(mdctx
, *digest
, outputlen
);
4608 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
4609 EVP_MD_CTX_free(mdctx
);
4611 EVP_MD_CTX_destroy(mdctx
);
4614 return SWITCH_STATUS_SUCCESS
;
4616 return SWITCH_STATUS_FALSE
;
4620 SWITCH_DECLARE(switch_status_t
) switch_digest_string(const char *digest_name
, char **digest_str
, const void *input
, switch_size_t inputLen
, unsigned int *outputlen
)
4622 unsigned char *digest
= NULL
;
4623 switch_status_t status
;
4627 status
= switch_digest(digest_name
, &digest
, input
, inputLen
, outputlen
);
4629 if (status
== SWITCH_STATUS_SUCCESS
) {
4630 if ((*digest_str
= malloc(*outputlen
* 2 + 1))) {
4631 for (x
= i
= 0; x
< *outputlen
; x
++) {
4632 b
= (digest
[x
] >> 4) & 15;
4633 (*digest_str
)[i
++] = b
+ (b
> 9 ? 'a' - 10 : '0');
4635 (*digest_str
)[i
++] = b
+ (b
> 9 ? 'a' - 10 : '0');
4638 (*digest_str
)[i
] = '\0';
4640 switch_safe_free(digest
);
4642 return SWITCH_STATUS_FALSE
;
4646 switch_safe_free(digest
);
4652 SWITCH_DECLARE(char *) switch_must_strdup(const char *_s
)
4654 char *s
= strdup(_s
);
4659 SWITCH_DECLARE(const char *) switch_memory_usage_stream(switch_stream_handle_t
*stream
)
4661 const char *status
= NULL
;
4664 * The mallinfo2() function was added in glibc 2.33.
4665 * https://man7.org/linux/man-pages/man3/mallinfo.3.html
4667 #if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 33)
4668 struct mallinfo2 mi
;
4672 stream
->write_function(stream
, "Total non-mmapped bytes (arena): %" SWITCH_SIZE_T_FMT
"\n", mi
.arena
);
4673 stream
->write_function(stream
, "# of free chunks (ordblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.ordblks
);
4674 stream
->write_function(stream
, "# of free fastbin blocks (smblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.smblks
);
4675 stream
->write_function(stream
, "# of mapped regions (hblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.hblks
);
4676 stream
->write_function(stream
, "Bytes in mapped regions (hblkhd): %" SWITCH_SIZE_T_FMT
"\n", mi
.hblkhd
);
4677 stream
->write_function(stream
, "Max. total allocated space (usmblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.usmblks
);
4678 stream
->write_function(stream
, "Free bytes held in fastbins (fsmblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.fsmblks
);
4679 stream
->write_function(stream
, "Total allocated space (uordblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.uordblks
);
4680 stream
->write_function(stream
, "Total free space (fordblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.fordblks
);
4681 stream
->write_function(stream
, "Topmost releasable block (keepcost): %" SWITCH_SIZE_T_FMT
"\n", mi
.keepcost
);
4687 stream
->write_function(stream
, "Total non-mmapped bytes (arena): %u\n", mi
.arena
);
4688 stream
->write_function(stream
, "# of free chunks (ordblks): %u\n", mi
.ordblks
);
4689 stream
->write_function(stream
, "# of free fastbin blocks (smblks): %u\n", mi
.smblks
);
4690 stream
->write_function(stream
, "# of mapped regions (hblks): %u\n", mi
.hblks
);
4691 stream
->write_function(stream
, "Bytes in mapped regions (hblkhd): %u\n", mi
.hblkhd
);
4692 stream
->write_function(stream
, "Max. total allocated space (usmblks): %u\n", mi
.usmblks
);
4693 stream
->write_function(stream
, "Free bytes held in fastbins (fsmblks): %u\n", mi
.fsmblks
);
4694 stream
->write_function(stream
, "Total allocated space (uordblks): %u\n", mi
.uordblks
);
4695 stream
->write_function(stream
, "Total free space (fordblks): %u\n", mi
.fordblks
);
4696 stream
->write_function(stream
, "Topmost releasable block (keepcost): %u\n", mi
.keepcost
);
4700 switch_goto_status(NULL
, done
);
4703 /* Based on: https://docs.microsoft.com/en-us/windows/win32/memory/enumerating-a-heap and https://docs.microsoft.com/en-us/windows/win32/memory/getting-process-heaps */
4705 SIZE_T BytesToAllocate
;
4708 DWORD NumberOfHeaps
;
4710 HANDLE hDefaultProcessHeap
;
4711 size_t CommittedSizeTotal
= 0;
4712 size_t UnCommittedSizeTotal
= 0;
4713 size_t SizeTotal
= 0;
4714 size_t OverheadTotal
= 0;
4716 NumberOfHeaps
= GetProcessHeaps(0, NULL
);
4717 Result
= SIZETMult(NumberOfHeaps
, sizeof(*aHeaps
), &BytesToAllocate
);
4718 if (Result
!= S_OK
) {
4719 switch_goto_status("SIZETMult failed.", done
);
4722 hDefaultProcessHeap
= GetProcessHeap();
4723 if (hDefaultProcessHeap
== NULL
) {
4724 switch_goto_status("Failed to retrieve the default process heap", done
);
4727 aHeaps
= (PHANDLE
)HeapAlloc(hDefaultProcessHeap
, 0, BytesToAllocate
);
4728 if (aHeaps
== NULL
) {
4729 switch_goto_status("HeapAlloc failed to allocate space for heaps", done
);
4732 HeapsLength
= NumberOfHeaps
;
4733 NumberOfHeaps
= GetProcessHeaps(HeapsLength
, aHeaps
);
4735 if (NumberOfHeaps
== 0) {
4736 switch_goto_status("Failed to retrieve heaps", cleanup
);
4737 } else if (NumberOfHeaps
> HeapsLength
) {
4739 * Compare the latest number of heaps with the original number of heaps.
4740 * If the latest number is larger than the original number, another
4741 * component has created a new heap and the buffer is too small.
4743 switch_goto_status("Another component created a heap between calls.", cleanup
);
4746 stream
->write_function(stream
, "Process has %d heaps.\n", HeapsLength
);
4747 for (HeapsIndex
= 0; HeapsIndex
< HeapsLength
; ++HeapsIndex
) {
4748 PROCESS_HEAP_ENTRY Entry
;
4749 HANDLE hHeap
= aHeaps
[HeapsIndex
];
4751 stream
->write_function(stream
, "Heap %d at address: %#p.\n", HeapsIndex
, aHeaps
[HeapsIndex
]);
4753 /* Lock the heap to prevent other threads from accessing the heap during enumeration. */
4754 if (HeapLock(hHeap
) == FALSE
) {
4755 switch_goto_status("Failed to lock heap.", cleanup
);
4758 Entry
.lpData
= NULL
;
4759 while (HeapWalk(hHeap
, &Entry
) != FALSE
) {
4760 if ((Entry
.wFlags
& PROCESS_HEAP_ENTRY_BUSY
) != 0) {
4761 } else if ((Entry
.wFlags
& PROCESS_HEAP_REGION
) != 0) {
4762 CommittedSizeTotal
+= Entry
.Region
.dwCommittedSize
;
4763 UnCommittedSizeTotal
+= Entry
.Region
.dwUnCommittedSize
;
4766 SizeTotal
+= Entry
.cbData
;
4767 OverheadTotal
+= Entry
.cbOverhead
;
4770 /* Unlock the heap to allow other threads to access the heap after enumeration has completed. */
4771 if (HeapUnlock(hHeap
) == FALSE
) {
4776 stream
->write_function(stream
, "Committed bytes: %" SWITCH_SIZE_T_FMT
"\n", CommittedSizeTotal
);
4777 stream
->write_function(stream
, "Uncommited bytes: %" SWITCH_SIZE_T_FMT
"\n", UnCommittedSizeTotal
);
4778 stream
->write_function(stream
, "Size: %" SWITCH_SIZE_T_FMT
"\n", SizeTotal
);
4779 stream
->write_function(stream
, "Overhead: %" SWITCH_SIZE_T_FMT
"\n", OverheadTotal
);
4782 HeapFree(hDefaultProcessHeap
, 0, aHeaps
);
4784 switch_goto_status("Memory usage statistics is not implemented on the current platform.", done
);
4794 * indent-tabs-mode:t
4799 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: