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
, ':');
764 if (bits
< 0 || bits
> 128) {
768 bits
= atoi(bit_str
);
769 switch_inet_pton(AF_INET6
, host
, (unsigned char *)ip
);
771 for (n
= bits
, i
= 0; i
< 16; i
++) {
773 maskv
->v6
.s6_addr
[i
] = 0xFF & ~(0xFF >> k
); /* k = 0 gives 0x00, k = 8 gives 0xFF */
777 if (bits
< 0 || bits
> 32) {
781 bits
= atoi(bit_str
);
782 switch_inet_pton(AF_INET
, host
, (unsigned char *)ip
);
783 ipv
->v4
= htonl(ipv
->v4
);
785 maskv
->v4
= 0xFFFFFFFF & ~(0xFFFFFFFF >> bits
);
794 SWITCH_DECLARE(char *) switch_find_end_paren(const char *s
, char open
, char close
)
796 const char *e
= NULL
;
799 while (s
&& *s
&& *s
== ' ') {
803 if (s
&& *s
== open
) {
805 for (e
= s
+ 1; e
&& *e
; e
++) {
806 if (*e
== open
&& open
!= close
) {
808 } else if (*e
== close
) {
817 return (e
&& *e
== close
) ? (char *) e
: NULL
;
820 SWITCH_DECLARE(switch_size_t
) switch_fd_read_line(int fd
, char *buf
, switch_size_t len
)
824 switch_size_t total
= 0;
827 while (total
+ 2 < len
&& (cur
= read(fd
, &c
, 1)) == 1) {
830 if (c
== '\r' || c
== '\n') {
840 #define DLINE_BLOCK_SIZE 1024
841 #define DLINE_MAX_SIZE 1048576
842 SWITCH_DECLARE(switch_size_t
) switch_fd_read_dline(int fd
, char **buf
, switch_size_t
*len
)
846 switch_size_t total
= 0;
848 switch_size_t ilen
= *len
;
851 *len
= ilen
= DLINE_BLOCK_SIZE
;
853 memset(data
, 0, ilen
);
857 while ((cur
= read(fd
, &c
, 1)) == 1) {
859 if (total
+ 2 >= ilen
) {
860 if (ilen
+ DLINE_BLOCK_SIZE
> DLINE_MAX_SIZE
) {
861 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "Single line limit reached!\n");
865 ilen
+= DLINE_BLOCK_SIZE
;
866 data
= realloc(data
, ilen
);
875 if (c
== '\r' || c
== '\n') {
890 SWITCH_DECLARE(switch_size_t
) switch_fp_read_dline(FILE *fd
, char **buf
, switch_size_t
*len
)
893 switch_size_t total
= 0;
895 switch_size_t ilen
= *len
;
898 *len
= ilen
= DLINE_BLOCK_SIZE
;
900 memset(data
, 0, ilen
);
904 //while ((c = fgetc(fd)) != EOF) {
906 while (fread(&c
, 1, 1, fd
) == 1) {
908 if (total
+ 2 >= ilen
) {
909 if (ilen
+ DLINE_BLOCK_SIZE
> DLINE_MAX_SIZE
) {
910 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_CRIT
, "Single line limit reached!\n");
914 ilen
+= DLINE_BLOCK_SIZE
;
915 data
= realloc(data
, ilen
);
924 if (c
== '\r' || c
== '\n') {
937 SWITCH_DECLARE(char *) switch_amp_encode(char *s
, char *buf
, switch_size_t len
)
945 for (p
= s
; x
< len
; p
++) {
949 if (x
+ 6 > len
- 1) {
961 if (x
+ 6 > len
- 1) {
973 if (x
+ 5 > len
- 1) {
984 if (x
+ 4 > len
- 1) {
994 if (x
+ 4 > len
- 1) {
1004 if (x
+ 1 > len
- 1) {
1021 static const char switch_b64_table
[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1022 #define B64BUFFLEN 1024
1023 SWITCH_DECLARE(switch_status_t
) switch_b64_encode(unsigned char *in
, switch_size_t ilen
, unsigned char *out
, switch_size_t olen
)
1025 int y
= 0, bytes
= 0;
1027 unsigned int b
= 0, l
= 0;
1029 for (x
= 0; x
< ilen
; x
++) {
1030 b
= (b
<< 8) + in
[x
];
1034 out
[bytes
++] = switch_b64_table
[(b
>> (l
-= 6)) % 64];
1035 if (bytes
>= (int)olen
- 1) {
1041 /* out[bytes++] = '\n'; */
1047 out
[bytes
++] = switch_b64_table
[((b
% 16) << (6 - l
)) % 64];
1050 while (l
< 6 && bytes
< (int)olen
- 1) {
1051 out
[bytes
++] = '=', l
+= 2;
1059 return SWITCH_STATUS_SUCCESS
;
1062 SWITCH_DECLARE(switch_size_t
) switch_b64_decode(const char *in
, char *out
, switch_size_t olen
)
1066 int b
= 0, c
, l
= 0, i
;
1071 for (i
= 0; i
< 256; i
++) {
1075 for (i
= 0; i
< 64; i
++) {
1076 l64
[(int) switch_b64_table
[i
]] = (char) i
;
1079 for (ip
= in
; ip
&& *ip
&& (*ip
!= '='); ip
++) {
1089 op
[ol
++] = (char) ((b
>> (l
-= 8)) % 256);
1090 if (ol
>= olen
- 1) {
1103 static int write_buf(int fd
, const char *buf
)
1106 int len
= (int) strlen(buf
);
1107 if (fd
&& write(fd
, buf
, len
) != len
) {
1115 SWITCH_DECLARE(switch_bool_t
) switch_simple_email(const char *to
,
1117 const char *headers
,
1118 const char *body
, const char *file
, const char *convert_cmd
, const char *convert_ext
)
1120 char *bound
= "XXXX_boundary_XXXX";
1121 const char *mime_type
= "audio/inline";
1122 char filename
[80], buf
[B64BUFFLEN
];
1123 int fd
= -1, ifd
= -1;
1124 int x
= 0, y
= 0, bytes
= 0, ilen
= 0;
1125 unsigned int b
= 0, l
= 0;
1126 unsigned char in
[B64BUFFLEN
];
1127 unsigned char out
[B64BUFFLEN
+ 512];
1128 char *dupfile
= NULL
, *ext
= NULL
;
1129 char *newfile
= NULL
;
1130 switch_bool_t rval
= SWITCH_FALSE
;
1131 const char *err
= NULL
;
1136 err
= "No to address specified";
1140 if (!zstr(file
) && !zstr(convert_cmd
) && !zstr(convert_ext
)) {
1141 if (strrchr(file
, '.')) {
1142 dupfile
= strdup(file
);
1143 if ((ext
= strrchr(dupfile
, '.'))) {
1145 newfile
= switch_mprintf("%s.%s", dupfile
, convert_ext
);
1150 char cmd
[1024] = "";
1151 switch_snprintf(cmd
, sizeof(cmd
), "%s %s %s", convert_cmd
, file
, newfile
);
1152 switch_system(cmd
, SWITCH_TRUE
);
1153 if (strcmp(file
, newfile
)) {
1156 switch_safe_free(newfile
);
1160 switch_safe_free(dupfile
);
1163 switch_snprintf(filename
, 80, "%s%smail.%d%04x", SWITCH_GLOBAL_dirs
.temp_dir
, SWITCH_PATH_SEPARATOR
, (int)(switch_time_t
) switch_epoch_time_now(NULL
), switch_rand() & 0xffff);
1165 if ((fd
= open(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644)) > -1) {
1167 if ((ifd
= open(file
, O_RDONLY
| O_BINARY
)) < 0) {
1168 rval
= SWITCH_FALSE
;
1169 err
= "Cannot open tmp file\n";
1174 if (!file
&& (!body
|| !switch_stristr("content-type", body
))) {
1179 switch_snprintf(buf
, B64BUFFLEN
, "MIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"%s\"\n", bound
);
1180 if (!write_buf(fd
, buf
)) {
1181 rval
= SWITCH_FALSE
;
1182 err
= "write error.";
1187 if (headers
&& !write_buf(fd
, headers
)) {
1188 rval
= SWITCH_FALSE
;
1189 err
= "write error.";
1193 if (!write_buf(fd
, "\n\n")) {
1194 rval
= SWITCH_FALSE
;
1195 err
= "write error.";
1200 if (body
&& switch_stristr("content-type", body
)) {
1201 switch_snprintf(buf
, B64BUFFLEN
, "--%s\n", bound
);
1203 switch_snprintf(buf
, B64BUFFLEN
, "--%s\nContent-Type: text/plain\n\n", bound
);
1205 if (!write_buf(fd
, buf
)) {
1206 rval
= SWITCH_FALSE
;
1207 err
= "write error.";
1213 if (!write_buf(fd
, body
)) {
1214 rval
= SWITCH_FALSE
;
1215 err
= "write error.";
1220 if (file
&& bound
) {
1221 const char *stipped_file
= switch_cut_path(file
);
1222 const char *new_type
;
1225 if ((ext
= strrchr(stipped_file
, '.'))) {
1227 if ((new_type
= switch_core_mime_ext2type(ext
))) {
1228 mime_type
= new_type
;
1232 switch_snprintf(buf
, B64BUFFLEN
,
1233 "\n\n--%s\nContent-Type: %s; name=\"%s\"\n"
1234 "Content-ID: <ATTACHED@freeswitch.org>\n"
1235 "Content-Transfer-Encoding: base64\n"
1236 "Content-Description: Sound attachment.\n"
1237 "Content-Disposition: attachment; filename=\"%s\"\n\n", bound
, mime_type
, stipped_file
, stipped_file
);
1238 if (!write_buf(fd
, buf
)) {
1239 rval
= SWITCH_FALSE
;
1240 err
= "write error.";
1244 while ((ilen
= read(ifd
, in
, B64BUFFLEN
))) {
1245 for (x
= 0; x
< ilen
; x
++) {
1246 b
= (b
<< 8) + in
[x
];
1249 out
[bytes
++] = switch_b64_table
[(b
>> (l
-= 6)) % 64];
1252 out
[bytes
++] = '\n';
1256 if (write(fd
, &out
, bytes
) != bytes
) {
1266 out
[bytes
++] = switch_b64_table
[((b
% 16) << (6 - l
)) % 64];
1270 out
[bytes
++] = '=', l
+= 2;
1272 if (write(fd
, &out
, bytes
) != bytes
) {
1279 switch_snprintf(buf
, B64BUFFLEN
, "\n\n--%s--\n.\n", bound
);
1281 if (!write_buf(fd
, buf
)) {
1282 rval
= SWITCH_FALSE
;
1283 err
= "write error.";
1295 from
= "freeswitch";
1299 char *to_arg
= switch_util_quote_shell_arg(to
);
1300 char *from_arg
= switch_util_quote_shell_arg(from
);
1302 switch_snprintf(buf
, B64BUFFLEN
, "\"\"%s\" -f %s %s %s < \"%s\"\"", runtime
.mailer_app
, from_arg
, runtime
.mailer_app_args
, to_arg
, filename
);
1304 switch_snprintf(buf
, B64BUFFLEN
, "/bin/cat %s | %s -f %s %s %s", filename
, runtime
.mailer_app
, from_arg
, runtime
.mailer_app_args
, to_arg
);
1306 switch_safe_free(to_arg
); switch_safe_free(from_arg
);
1308 if (switch_system(buf
, SWITCH_TRUE
) < 0) {
1309 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Unable to execute command: %s\n", buf
);
1310 err
= "execute error";
1311 rval
= SWITCH_FALSE
;
1316 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG
, "Emailed file [%s] to [%s]\n", filename
, to
);
1318 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_DEBUG
, "Emailed data to [%s]\n", to
);
1330 if (!zstr_buf(filename
) && unlink(filename
) != 0) {
1331 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "Failed to delete file [%s]\n", filename
);
1344 if (rval
!= SWITCH_TRUE
) {
1345 if (zstr(err
)) err
= "Unknown Error";
1347 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "EMAIL NOT SENT, error [%s]\n", err
);
1353 SWITCH_DECLARE(switch_bool_t
) switch_is_lan_addr(const char *ip
)
1356 return SWITCH_FALSE
;
1358 return (strncmp(ip
, "10.", 3) && /* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */
1359 strncmp(ip
, "192.168.", 8) && /* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */
1360 strncmp(ip
, "127.", 4) && /* 127.0.0.0 - 127.255.255.255 (127/8 prefix) */
1361 strncmp(ip
, "255.", 4) &&
1362 strncmp(ip
, "0.", 2) &&
1363 strncmp(ip
, "1.", 2) &&
1364 strncmp(ip
, "2.", 2) &&
1365 strncmp(ip
, "172.16.", 7) && /* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */
1366 strncmp(ip
, "172.17.", 7) &&
1367 strncmp(ip
, "172.18.", 7) &&
1368 strncmp(ip
, "172.19.", 7) &&
1369 strncmp(ip
, "172.20.", 7) &&
1370 strncmp(ip
, "172.21.", 7) &&
1371 strncmp(ip
, "172.22.", 7) &&
1372 strncmp(ip
, "172.23.", 7) &&
1373 strncmp(ip
, "172.24.", 7) &&
1374 strncmp(ip
, "172.25.", 7) &&
1375 strncmp(ip
, "172.26.", 7) &&
1376 strncmp(ip
, "172.27.", 7) &&
1377 strncmp(ip
, "172.28.", 7) &&
1378 strncmp(ip
, "172.29.", 7) &&
1379 strncmp(ip
, "172.30.", 7) &&
1380 strncmp(ip
, "172.31.", 7) &&
1381 strncmp(ip
, "192.0.2.", 8) && /* 192.0.2.0 - 192.0.2.255 (192.0.2/24 prefix) */
1382 strncmp(ip
, "169.254.", 8) /* 169.254.0.0 - 169.254.255.255 (169.254/16 prefix) */
1383 )? SWITCH_FALSE
: SWITCH_TRUE
;
1386 SWITCH_DECLARE(switch_bool_t
) switch_ast2regex(const char *pat
, char *rbuf
, size_t len
)
1388 const char *p
= pat
;
1391 return SWITCH_FALSE
;
1394 memset(rbuf
, 0, len
);
1396 *(rbuf
+ strlen(rbuf
)) = '^';
1400 strncat(rbuf
, "[2-9]", len
- strlen(rbuf
));
1401 } else if (*p
== 'X') {
1402 strncat(rbuf
, "[0-9]", len
- strlen(rbuf
));
1403 } else if (*p
== 'Z') {
1404 strncat(rbuf
, "[1-9]", len
- strlen(rbuf
));
1405 } else if (*p
== '.') {
1406 strncat(rbuf
, ".*", len
- strlen(rbuf
));
1407 } else if (strlen(rbuf
) < len
- 1) {
1408 *(rbuf
+ strlen(rbuf
)) = *p
;
1412 *(rbuf
+ strlen(rbuf
)) = '$';
1414 return strcmp(pat
, rbuf
) ? SWITCH_TRUE
: SWITCH_FALSE
;
1417 SWITCH_DECLARE(char *) switch_replace_char(char *str
, char from
, char to
, switch_bool_t dup
)
1428 for (; p
&& *p
; p
++) {
1437 SWITCH_DECLARE(char *) switch_pool_strip_whitespace(switch_memory_pool_t
*pool
, const char *str
)
1439 const char *sp
= str
;
1444 return switch_core_strdup(pool
, SWITCH_BLANK_STRING
);
1447 while ((*sp
== 13 ) || (*sp
== 10 ) || (*sp
== 9 ) || (*sp
== 32) || (*sp
== 11) ) {
1452 return switch_core_strdup(pool
, SWITCH_BLANK_STRING
);
1455 s
= switch_core_strdup(pool
, sp
);
1458 if ((len
= strlen(s
)) > 0) {
1461 while ((p
>= s
) && ((*p
== 13 ) || (*p
== 10 ) || (*p
== 9 ) || (*p
== 32) || (*p
== 11))) {
1469 SWITCH_DECLARE(char *) switch_strip_whitespace(const char *str
)
1471 const char *sp
= str
;
1476 return strdup(SWITCH_BLANK_STRING
);
1479 while ((*sp
== 13 ) || (*sp
== 10 ) || (*sp
== 9 ) || (*sp
== 32) || (*sp
== 11) ) {
1484 return strdup(SWITCH_BLANK_STRING
);
1490 if ((len
= strlen(s
)) > 0) {
1493 while ((p
>= s
) && ((*p
== 13 ) || (*p
== 10 ) || (*p
== 9 ) || (*p
== 32) || (*p
== 11))) {
1501 SWITCH_DECLARE(char *) switch_strip_spaces(char *str
, switch_bool_t dup
)
1508 return dup
? strdup(SWITCH_BLANK_STRING
) : sp
;
1511 while (*sp
== ' ') {
1526 if ((len
= strlen(s
)) > 0) {
1529 while (p
&& *p
&& (p
>= s
) && *p
== ' ') {
1537 SWITCH_DECLARE(char *) switch_strip_commas(char *in
, char *out
, switch_size_t len
)
1539 char *p
= in
, *q
= out
;
1541 switch_size_t x
= 0;
1543 for (; p
&& *p
; p
++) {
1544 if ((*p
> 47 && *p
< 58)) {
1551 } else if (*p
!= ',') {
1560 SWITCH_DECLARE(char *) switch_strip_nonnumerics(char *in
, char *out
, switch_size_t len
)
1562 char *p
= in
, *q
= out
;
1564 switch_size_t x
= 0;
1565 /* valid are 0 - 9, period (.), minus (-), and plus (+) - remove all others */
1566 for (; p
&& *p
; p
++) {
1567 if ((*p
> 47 && *p
< 58) || *p
== '.' || *p
== '-' || *p
== '+') {
1580 SWITCH_DECLARE(char *) switch_separate_paren_args(char *str
)
1585 if ((args
= strchr(str
, '('))) {
1596 } else if (br
> 1 && *e
== ')') {
1598 } else if (br
== 1 && *e
== ')') {
1609 SWITCH_DECLARE(switch_bool_t
) switch_is_uint_in_range(const char *str
, unsigned int from
, unsigned int to
)
1611 unsigned int number
;
1612 const char *original_str
= str
;
1614 if (str
== NULL
|| *str
== '\0' || from
> to
) {
1615 return SWITCH_FALSE
;
1618 for (; *str
!= '\0'; str
++) {
1619 if (!isdigit(*str
)) {
1620 return SWITCH_FALSE
;
1624 number
= atoi(original_str
);
1626 if (number
< from
|| number
> to
) {
1627 return SWITCH_FALSE
;
1633 SWITCH_DECLARE(switch_bool_t
) switch_is_number(const char *str
)
1636 switch_bool_t r
= SWITCH_TRUE
;
1638 if (*str
== '-' || *str
== '+') {
1642 for (p
= str
; p
&& *p
; p
++) {
1643 if (!(*p
== '.' || (*p
> 47 && *p
< 58))) {
1652 SWITCH_DECLARE(switch_bool_t
) switch_is_leading_number(const char *str
)
1655 switch_bool_t r
= SWITCH_FALSE
;
1657 if (*str
== '-' || *str
== '+') {
1661 for (p
= str
; p
&& *p
; p
++) {
1662 if ((*p
== '.' || (*p
> 47 && *p
< 58))) {
1671 SWITCH_DECLARE(const char *) switch_stristr(const char *instr
, const char *str
)
1674 ** Rev History: 16/07/97 Greg Thayer Optimized
1675 ** 07/04/95 Bob Stout ANSI-fy
1676 ** 02/03/94 Fred Cole Original
1677 ** 09/01/03 Bob Stout Bug fix (lines 40-41) per Fred Bulback
1679 ** Hereby donated to public domain.
1681 const char *pptr
, *sptr
, *start
;
1686 for (start
= str
; *start
; start
++) {
1687 /* find start of pattern in string */
1688 for (; ((*start
) && (switch_toupper(*start
) != switch_toupper(*instr
))); start
++);
1696 while (switch_toupper(*sptr
) == switch_toupper(*pptr
)) {
1700 /* if end of pattern then pattern was found */
1711 #ifdef HAVE_GETIFADDRS
1712 #include <ifaddrs.h>
1713 static int get_netmask(struct sockaddr_in
*me
, int *mask
)
1715 struct ifaddrs
*ifaddrs
, *i
= NULL
;
1717 if (!me
|| getifaddrs(&ifaddrs
) < 0) {
1721 for (i
= ifaddrs
; i
; i
= i
->ifa_next
) {
1722 struct sockaddr_in
*s
= (struct sockaddr_in
*) i
->ifa_addr
;
1723 struct sockaddr_in
*m
= (struct sockaddr_in
*) i
->ifa_netmask
;
1725 if (s
&& m
&& s
->sin_family
== AF_INET
&& s
->sin_addr
.s_addr
== me
->sin_addr
.s_addr
) {
1726 *mask
= m
->sin_addr
.s_addr
;
1727 freeifaddrs(ifaddrs
);
1732 freeifaddrs(ifaddrs
);
1736 #elif defined(__linux__)
1738 #include <sys/ioctl.h>
1740 static int get_netmask(struct sockaddr_in
*me
, int *mask
)
1743 static struct ifreq ifreqs
[20] = { {{{0}}} };
1744 struct ifconf ifconf
;
1749 memset(&ifconf
, 0, sizeof(ifconf
));
1750 ifconf
.ifc_buf
= (char *) (ifreqs
);
1751 ifconf
.ifc_len
= sizeof(ifreqs
);
1754 if ((sock
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
1758 if (ioctl(sock
, SIOCGIFCONF
, (char *) &ifconf
) < 0) {
1762 nifaces
= ifconf
.ifc_len
/ sizeof(struct ifreq
);
1764 for (i
= 0; i
< nifaces
; i
++) {
1765 struct sockaddr_in
*sin
= NULL
;
1768 ioctl(sock
, SIOCGIFADDR
, &ifreqs
[i
]);
1769 sin
= (struct sockaddr_in
*) &ifreqs
[i
].ifr_addr
;
1772 if (ip
.s_addr
== me
->sin_addr
.s_addr
) {
1773 ioctl(sock
, SIOCGIFNETMASK
, &ifreqs
[i
]);
1774 sin
= (struct sockaddr_in
*) &ifreqs
[i
].ifr_addr
;
1775 /* mask = sin->sin_addr; */
1776 *mask
= sin
->sin_addr
.s_addr
;
1790 #elif defined(WIN32)
1792 static int get_netmask(struct sockaddr_in
*me
, int *mask
)
1794 SOCKET sock
= WSASocket(AF_INET
, SOCK_DGRAM
, 0, 0, 0, 0);
1795 INTERFACE_INFO interfaces
[20];
1796 unsigned long bytes
;
1797 int interface_count
, x
;
1802 if (sock
== SOCKET_ERROR
) {
1806 if (WSAIoctl(sock
, SIO_GET_INTERFACE_LIST
, 0, 0, &interfaces
, sizeof(interfaces
), &bytes
, 0, 0) == SOCKET_ERROR
) {
1811 interface_count
= bytes
/ sizeof(INTERFACE_INFO
);
1813 for (x
= 0; x
< interface_count
; ++x
) {
1814 struct sockaddr_in
*addr
= (struct sockaddr_in
*) &(interfaces
[x
].iiAddress
);
1816 if (addr
->sin_addr
.s_addr
== me
->sin_addr
.s_addr
) {
1817 struct sockaddr_in
*netmask
= (struct sockaddr_in
*) &(interfaces
[x
].iiNetmask
);
1818 *mask
= netmask
->sin_addr
.s_addr
;
1831 static int get_netmask(struct sockaddr_in
*me
, int *mask
)
1839 SWITCH_DECLARE(switch_status_t
) switch_resolve_host(const char *host
, char *buf
, size_t buflen
)
1842 struct addrinfo
*ai
;
1844 if (getaddrinfo(host
, 0, 0, &ai
)) {
1845 return SWITCH_STATUS_FALSE
;
1848 get_addr(buf
, buflen
, ai
->ai_addr
, sizeof(struct sockaddr_storage
));
1852 return SWITCH_STATUS_SUCCESS
;
1856 SWITCH_DECLARE(switch_status_t
) switch_find_local_ip(char *buf
, int len
, int *mask
, int family
)
1858 switch_status_t status
= SWITCH_STATUS_FALSE
;
1860 char *force_local_ip_v4
= switch_core_get_variable_dup("force_local_ip_v4");
1861 char *force_local_ip_v6
= switch_core_get_variable_dup("force_local_ip_v6");
1865 SOCKADDR_STORAGE l_address
;
1867 struct addrinfo
*address_info
;
1874 int tmp_socket
= -1, on
= 1;
1880 if (force_local_ip_v4
) {
1881 switch_copy_string(buf
, force_local_ip_v4
, len
);
1882 switch_safe_free(force_local_ip_v4
);
1883 switch_safe_free(force_local_ip_v6
);
1884 return SWITCH_STATUS_SUCCESS
;
1887 if (force_local_ip_v6
) {
1888 switch_copy_string(buf
, force_local_ip_v6
, len
);
1889 switch_safe_free(force_local_ip_v4
);
1890 switch_safe_free(force_local_ip_v6
);
1891 return SWITCH_STATUS_SUCCESS
;
1894 switch_safe_free(force_local_ip_v4
);
1895 switch_safe_free(force_local_ip_v6
);
1906 switch_copy_string(buf
, "127.0.0.1", len
);
1907 base
= "82.45.148.209";
1910 switch_copy_string(buf
, "::1", len
);
1911 base
= "2001:503:BA3E::2:30"; /* DNS Root server A */
1919 tmp_socket
= socket(family
, SOCK_DGRAM
, 0);
1921 getaddrinfo(base
, NULL
, NULL
, &address_info
);
1923 if (!address_info
|| WSAIoctl(tmp_socket
,
1924 SIO_ROUTING_INTERFACE_QUERY
,
1925 address_info
->ai_addr
, (DWORD
) address_info
->ai_addrlen
, &l_address
, sizeof(l_address
), (LPDWORD
) & l_address_len
, NULL
,
1928 closesocket(tmp_socket
);
1930 freeaddrinfo(address_info
);
1935 closesocket(tmp_socket
);
1936 freeaddrinfo(address_info
);
1938 if (!getnameinfo((const struct sockaddr
*) &l_address
, l_address_len
, buf
, len
, NULL
, 0, NI_NUMERICHOST
)) {
1939 status
= SWITCH_STATUS_SUCCESS
;
1941 get_netmask((struct sockaddr_in
*) &l_address
, mask
);
1949 struct sockaddr_in iface_out
;
1950 struct sockaddr_in remote
;
1951 memset(&remote
, 0, sizeof(struct sockaddr_in
));
1953 remote
.sin_family
= AF_INET
;
1954 remote
.sin_addr
.s_addr
= inet_addr(base
);
1955 remote
.sin_port
= htons(4242);
1957 memset(&iface_out
, 0, sizeof(iface_out
));
1958 if ( (tmp_socket
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1 ) {
1962 if (setsockopt(tmp_socket
, SOL_SOCKET
, SO_BROADCAST
, &on
, sizeof(on
)) == -1) {
1966 if (connect(tmp_socket
, (struct sockaddr
*) &remote
, sizeof(struct sockaddr_in
)) == -1) {
1970 ilen
= sizeof(iface_out
);
1971 if (getsockname(tmp_socket
, (struct sockaddr
*) &iface_out
, &ilen
) == -1) {
1975 if (iface_out
.sin_addr
.s_addr
== 0) {
1979 switch_copy_string(buf
, get_addr(abuf
, sizeof(abuf
), (struct sockaddr
*) &iface_out
, sizeof(struct sockaddr_storage
)), len
);
1981 get_netmask((struct sockaddr_in
*) &iface_out
, mask
);
1984 status
= SWITCH_STATUS_SUCCESS
;
1989 struct sockaddr_in6 iface_out
;
1990 struct sockaddr_in6 remote
;
1991 memset(&remote
, 0, sizeof(struct sockaddr_in6
));
1993 remote
.sin6_family
= AF_INET6
;
1994 switch_inet_pton(AF_INET6
, base
, &remote
.sin6_addr
);
1995 remote
.sin6_port
= htons(4242);
1997 memset(&iface_out
, 0, sizeof(iface_out
));
1998 if ( (tmp_socket
= socket(AF_INET6
, SOCK_DGRAM
, 0)) == -1 ) {
2002 if (connect(tmp_socket
, (struct sockaddr
*) &remote
, sizeof(remote
)) == -1) {
2006 ilen
= sizeof(iface_out
);
2007 if (getsockname(tmp_socket
, (struct sockaddr
*) &iface_out
, &ilen
) == -1) {
2011 inet_ntop(AF_INET6
, (const void *) &iface_out
.sin6_addr
, buf
, len
- 1);
2012 status
= SWITCH_STATUS_SUCCESS
;
2018 if (tmp_socket
>= 0) {
2026 #ifdef HAVE_GETIFADDRS
2027 # include <ifaddrs.h>
2028 # include <net/if.h>
2030 SWITCH_DECLARE(switch_status_t
) switch_find_interface_ip(char *buf
, int len
, int *mask
, const char *ifname
, int family
)
2032 switch_status_t status
= SWITCH_STATUS_FALSE
;
2034 #ifdef HAVE_GETIFADDRS
2036 struct ifaddrs
*addrs
, *addr
;
2039 for(addr
= addrs
; addr
; addr
= addr
->ifa_next
)
2041 if (!(addr
->ifa_flags
& IFF_UP
)) continue; // Address is not UP
2042 if (!addr
->ifa_addr
) continue; // No address set
2043 if (!addr
->ifa_netmask
) continue; // No netmask set
2044 if (family
!= AF_UNSPEC
&& addr
->ifa_addr
->sa_family
!= family
) continue; // Not the address family we're looking for
2045 if (strcmp(addr
->ifa_name
, ifname
)) continue; // Not the interface we're looking for
2047 switch(addr
->ifa_addr
->sa_family
) {
2049 inet_ntop(AF_INET
, &( ((struct sockaddr_in
*)(addr
->ifa_addr
))->sin_addr
), buf
, len
- 1);
2052 inet_ntop(AF_INET6
, &( ((struct sockaddr_in6
*)(addr
->ifa_addr
))->sin6_addr
), buf
, len
- 1);
2058 if (mask
&& addr
->ifa_netmask
->sa_family
== AF_INET
) {
2059 *mask
= ((struct sockaddr_in
*)(addr
->ifa_addr
))->sin_addr
.s_addr
;
2062 status
= SWITCH_STATUS_SUCCESS
;
2067 #elif defined(__linux__)
2069 // TODO Not implemented, contributions welcome.
2071 #elif defined(WIN32)
2073 // TODO Not implemented, contributions welcome.
2081 SWITCH_DECLARE(switch_time_t
) switch_str_time(const char *in
)
2083 switch_time_exp_t tm
= { 0 }, local_tm
= { 0 };
2084 int proceed
= 0, ovector
[30], time_only
= 0;
2085 switch_regex_t
*re
= NULL
;
2086 char replace
[1024] = "";
2087 switch_time_t ret
= 0, local_time
= 0;
2088 char *pattern
= "^(\\d+)-(\\d+)-(\\d+)\\s*(\\d*):{0,1}(\\d*):{0,1}(\\d*)";
2089 char *pattern2
= "^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})";
2090 char *pattern3
= "^(\\d*):{0,1}(\\d*):{0,1}(\\d*)$";
2092 switch_time_exp_lt(&tm
, switch_micro_time_now());
2095 if ((time_only
= switch_regex_perform(in
, pattern3
, &re
, ovector
, sizeof(ovector
) / sizeof(ovector
[0])))) {
2100 tm
.tm_year
= tm
.tm_mon
= tm
.tm_mday
= tm
.tm_hour
= tm
.tm_min
= tm
.tm_sec
= tm
.tm_usec
= 0;
2102 if (!(proceed
= switch_regex_perform(in
, pattern
, &re
, ovector
, sizeof(ovector
) / sizeof(ovector
[0])))) {
2103 switch_regex_safe_free(re
);
2104 proceed
= switch_regex_perform(in
, pattern2
, &re
, ovector
, sizeof(ovector
) / sizeof(ovector
[0]));
2108 if (proceed
|| time_only
) {
2110 if (time_only
> 1) {
2111 switch_regex_copy_substring(in
, ovector
, time_only
, 1, replace
, sizeof(replace
));
2112 tm
.tm_hour
= atoi(replace
);
2115 if (time_only
> 2) {
2116 switch_regex_copy_substring(in
, ovector
, time_only
, 2, replace
, sizeof(replace
));
2117 tm
.tm_min
= atoi(replace
);
2120 if (time_only
> 3) {
2121 switch_regex_copy_substring(in
, ovector
, time_only
, 3, replace
, sizeof(replace
));
2122 tm
.tm_sec
= atoi(replace
);
2126 switch_regex_copy_substring(in
, ovector
, proceed
, 1, replace
, sizeof(replace
));
2127 tm
.tm_year
= atoi(replace
) - 1900;
2131 switch_regex_copy_substring(in
, ovector
, proceed
, 2, replace
, sizeof(replace
));
2132 tm
.tm_mon
= atoi(replace
) - 1;
2136 switch_regex_copy_substring(in
, ovector
, proceed
, 3, replace
, sizeof(replace
));
2137 tm
.tm_mday
= atoi(replace
);
2141 switch_regex_copy_substring(in
, ovector
, proceed
, 4, replace
, sizeof(replace
));
2142 tm
.tm_hour
= atoi(replace
);
2146 switch_regex_copy_substring(in
, ovector
, proceed
, 5, replace
, sizeof(replace
));
2147 tm
.tm_min
= atoi(replace
);
2151 switch_regex_copy_substring(in
, ovector
, proceed
, 6, replace
, sizeof(replace
));
2152 tm
.tm_sec
= atoi(replace
);
2155 switch_regex_safe_free(re
);
2157 switch_time_exp_get(&local_time
, &tm
);
2158 switch_time_exp_lt(&local_tm
, local_time
);
2159 tm
.tm_isdst
= local_tm
.tm_isdst
;
2160 tm
.tm_gmtoff
= local_tm
.tm_gmtoff
;
2162 switch_time_exp_gmt_get(&ret
, &tm
);
2166 switch_regex_safe_free(re
);
2171 SWITCH_DECLARE(const char *) switch_priority_name(switch_priority_t priority
)
2173 switch (priority
) { /*lol */
2174 case SWITCH_PRIORITY_NORMAL
:
2176 case SWITCH_PRIORITY_LOW
:
2178 case SWITCH_PRIORITY_HIGH
:
2185 static char RFC2833_CHARS
[] = "0123456789*#ABCDF";
2188 /* Copyright (c) 1996 by Internet Software Consortium.
2190 * Permission to use, copy, modify, and distribute this software for any
2191 * purpose with or without fee is hereby granted, provided that the above
2192 * copyright notice and this permission notice appear in all copies.
2194 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
2195 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
2196 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
2197 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
2198 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
2199 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
2200 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2210 #include <sys/types.h>
2213 * WARNING: Don't even consider trying to compile this on a system where
2214 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
2217 static const char *switch_inet_ntop4(const unsigned char *src
, char *dst
, size_t size
);
2219 static const char *switch_inet_ntop6(const unsigned char *src
, char *dst
, size_t size
);
2223 * inet_ntop(af, src, dst, size)
2224 * convert a network format address to presentation format.
2226 * pointer to presentation format address (`dst'), or NULL (see errno).
2230 SWITCH_DECLARE(const char *) switch_inet_ntop(int af
, void const *src
, char *dst
, size_t size
)
2235 return switch_inet_ntop4(src
, dst
, size
);
2238 return switch_inet_ntop6(src
, dst
, size
);
2247 * inet_ntop4(src, dst, size)
2248 * format an IPv4 address, more or less like inet_ntoa()
2250 * `dst' (as a const)
2252 * (1) uses no statics
2253 * (2) takes a unsigned char* not an in_addr as input
2257 static const char *switch_inet_ntop4(const unsigned char *src
, char *dst
, size_t size
)
2259 static const char fmt
[] = "%u.%u.%u.%u";
2260 char tmp
[sizeof "255.255.255.255"];
2262 if (switch_snprintf(tmp
, sizeof tmp
, fmt
, src
[0], src
[1], src
[2], src
[3]) >= (int) size
) {
2266 return strcpy(dst
, tmp
);
2269 #if HAVE_SIN6 || defined(NTDDI_VERSION)
2271 * inet_ntop6(src, dst, size)
2272 * convert IPv6 binary address into presentation (printable) format
2276 static const char *switch_inet_ntop6(unsigned char const *src
, char *dst
, size_t size
)
2279 * Note that int32_t and int16_t need only be "at least" large enough
2280 * to contain a value of the specified size. On some systems, like
2281 * Crays, there is no such thing as an integer variable with 16 bits.
2282 * Keep this in mind if you think this function should have been coded
2283 * to use pointer overlays. All the world's not a VAX.
2285 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp
;
2291 unsigned int words
[8];
2296 * Copy the input (bytewise) array into a wordwise array.
2297 * Find the longest run of 0x00's in src[] for :: shorthanding.
2299 for (i
= 0; i
< 16; i
+= 2)
2300 words
[i
/ 2] = (src
[i
] << 8) | (src
[i
+ 1]);
2303 for (i
= 0; i
< 8; i
++) {
2304 if (words
[i
] == 0) {
2306 cur
.base
= i
, cur
.len
= 1;
2310 if (cur
.base
!= -1) {
2311 if (best
.base
== -1 || cur
.len
> best
.len
)
2317 if (cur
.base
!= -1) {
2318 if (best
.base
== -1 || cur
.len
> best
.len
)
2321 if (best
.base
!= -1 && best
.len
< 2)
2325 * Format the result.
2328 for (i
= 0; i
< 8; i
++) {
2329 /* Are we inside the best run of 0x00's? */
2330 if (best
.base
!= -1 && i
>= best
.base
&& i
< (best
.base
+ best
.len
)) {
2335 /* Are we following an initial run of 0x00s or any real hex? */
2338 /* Is this address an encapsulated IPv4? */
2339 if (i
== 6 && best
.base
== 0 && (best
.len
== 6 || (best
.len
== 5 && words
[5] == 0xffff))) {
2340 if (!switch_inet_ntop4(src
+ 12, tp
, sizeof tmp
- (tp
- tmp
)))
2345 tp
+= sprintf(tp
, "%x", words
[i
]);
2347 /* Was it a trailing run of 0x00's? */
2348 if (best
.base
!= -1 && (best
.base
+ best
.len
) == 8)
2353 * Check for overflow, copy, and we're done.
2355 if ((size_t) (tp
- tmp
) >= size
) {
2359 return strcpy(dst
, tmp
);
2365 SWITCH_DECLARE(int) get_addr_int(switch_sockaddr_t
*sa
)
2367 struct sockaddr_in
*s
= (struct sockaddr_in
*) &sa
->sa
;
2369 return ntohs((unsigned short) s
->sin_addr
.s_addr
);
2372 SWITCH_DECLARE(int) switch_cmp_addr(switch_sockaddr_t
*sa1
, switch_sockaddr_t
*sa2
, switch_bool_t ip_only
)
2374 struct sockaddr_in
*s1
;
2375 struct sockaddr_in
*s2
;
2377 struct sockaddr_in6
*s16
;
2378 struct sockaddr_in6
*s26
;
2380 struct sockaddr
*ss1
;
2381 struct sockaddr
*ss2
;
2386 s1
= (struct sockaddr_in
*) &sa1
->sa
;
2387 s2
= (struct sockaddr_in
*) &sa2
->sa
;
2389 s16
= (struct sockaddr_in6
*) &sa1
->sa
;
2390 s26
= (struct sockaddr_in6
*) &sa2
->sa
;
2392 ss1
= (struct sockaddr
*) &sa1
->sa
;
2393 ss2
= (struct sockaddr
*) &sa2
->sa
;
2395 if (ss1
->sa_family
!= ss2
->sa_family
)
2398 switch (ss1
->sa_family
) {
2401 return (s1
->sin_addr
.s_addr
== s2
->sin_addr
.s_addr
);
2403 return (s1
->sin_addr
.s_addr
== s2
->sin_addr
.s_addr
&& s1
->sin_port
== s2
->sin_port
);
2410 if (s16
->sin6_port
!= s26
->sin6_port
) return 0;
2413 for (i
= 0; i
< 4; i
++) {
2414 if (*((int32_t *) s16
->sin6_addr
.s6_addr
+ i
) != *((int32_t *) s26
->sin6_addr
.s6_addr
+ i
)) return 0;
2425 SWITCH_DECLARE(int) switch_cp_addr(switch_sockaddr_t
*sa1
, switch_sockaddr_t
*sa2
)
2427 struct sockaddr_in
*s1
;
2428 struct sockaddr_in
*s2
;
2430 struct sockaddr_in6
*s16
;
2431 struct sockaddr_in6
*s26
;
2433 struct sockaddr
*ss1
;
2434 //struct sockaddr *ss2;
2439 s1
= (struct sockaddr_in
*) &sa1
->sa
;
2440 s2
= (struct sockaddr_in
*) &sa2
->sa
;
2442 s16
= (struct sockaddr_in6
*) &sa1
->sa
;
2443 s26
= (struct sockaddr_in6
*) &sa2
->sa
;
2445 ss1
= (struct sockaddr
*) &sa1
->sa
;
2446 //ss2 = (struct sockaddr *) &sa2->sa;
2448 sa1
->port
= sa2
->port
;
2449 sa1
->family
= sa2
->family
;
2451 sa1
->sa
.sin
.sin_family
= sa2
->family
;
2453 switch (ss1
->sa_family
) {
2455 s1
->sin_addr
.s_addr
= s2
->sin_addr
.s_addr
;
2456 s1
->sin_port
= s2
->sin_port
;
2463 s16
->sin6_port
= s26
->sin6_port
;
2465 for (i
= 0; i
< 4; i
++) {
2466 *((int32_t *) s16
->sin6_addr
.s6_addr
+ i
) = *((int32_t *) s26
->sin6_addr
.s6_addr
+ i
);
2476 SWITCH_DECLARE(char *) get_addr6(char *buf
, switch_size_t len
, struct sockaddr_in6
*sa
, socklen_t salen
)
2482 #if defined(NTDDI_VERSION)
2483 switch_inet_ntop6((unsigned char*)&(sa
->sin6_addr
), buf
, len
);
2485 inet_ntop(AF_INET6
, &(sa
->sin6_addr
), buf
, len
);
2492 SWITCH_DECLARE(char *) get_addr(char *buf
, switch_size_t len
, struct sockaddr
*sa
, socklen_t salen
)
2498 getnameinfo(sa
, salen
, buf
, (socklen_t
) len
, NULL
, 0, NI_NUMERICHOST
);
2503 SWITCH_DECLARE(unsigned short) get_port(struct sockaddr
*sa
)
2505 unsigned short port
= 0;
2507 switch (sa
->sa_family
) {
2509 port
= ntohs(((struct sockaddr_in
*) sa
)->sin_port
);
2512 port
= ntohs(((struct sockaddr_in6
*) sa
)->sin6_port
);
2519 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
)
2521 char host
[NI_MAXHOST
], serv
[NI_MAXSERV
];
2522 struct sockaddr_in6 si6
;
2523 const struct sockaddr
*addr
;
2526 if (flags
& SWITCH_URI_NO_SCOPE
&& sa
->family
== AF_INET6
) {
2527 memcpy(&si6
, &sa
->sa
, sa
->salen
);
2528 si6
.sin6_scope_id
= 0;
2530 addr
= (const struct sockaddr
*) &si6
;
2532 addr
= (const struct sockaddr
*) (intptr_t) & sa
->sa
;
2535 if (getnameinfo(addr
, sa
->salen
, host
, sizeof(host
), serv
, sizeof(serv
),
2536 ((flags
& SWITCH_URI_NUMERIC_HOST
) ? NI_NUMERICHOST
: 0) | ((flags
& SWITCH_URI_NUMERIC_PORT
) ? NI_NUMERICSERV
: 0)) != 0) {
2540 colon
= strchr(host
, ':');
2542 return switch_snprintf(uri
, size
, "%s:%s%s%s%s%s%s%s", scheme
,
2543 user
? user
: "", user
? "@" : "", colon
? "[" : "", host
, colon
? "]" : "", serv
[0] ? ":" : "", serv
[0] ? serv
: "");
2546 SWITCH_DECLARE(char) switch_rfc2833_to_char(int event
)
2548 if (event
> -1 && event
< (int32_t) sizeof(RFC2833_CHARS
)) {
2549 return RFC2833_CHARS
[event
];
2554 SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key
)
2557 unsigned char counter
= 0;
2559 key
= (char) switch_toupper(key
);
2560 for (c
= RFC2833_CHARS
; *c
; c
++) {
2569 SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t
*pool
, char *in
, const char *delim
, char esc
)
2573 int count
= 1, i
= 0;
2591 data
= switch_core_alloc(pool
, strlen(in
) + count
);
2608 /* Helper function used when separating strings to unescape a character. The
2609 supported characters are:
2616 Any other character is returned as it was received. */
2617 static char unescape_char(char escaped
)
2635 unescaped
= escaped
;
2640 SWITCH_DECLARE(char *) switch_escape_string(const char *in
, char *out
, switch_size_t outlen
)
2645 for (p
= in
; *p
; p
++) {
2678 SWITCH_DECLARE(char *) switch_escape_string_pool(const char *in
, switch_memory_pool_t
*pool
)
2680 size_t len
= strlen(in
) * 2 + 1;
2681 char *buf
= switch_core_alloc(pool
, len
);
2682 return switch_escape_string(in
, buf
, len
);
2685 /* Helper function used when separating strings to remove quotes, leading /
2686 trailing spaces, and to convert escaped characters. */
2687 static char *cleanup_separated_string(char *str
, char delim
)
2693 int inside_quotes
= 0;
2695 /* Skip initial whitespace */
2696 for (ptr
= str
; *ptr
== ' '; ++ptr
) {
2699 for (start
= dest
= ptr
; *ptr
; ++ptr
) {
2703 if (*ptr
== ESCAPE_META
) {
2705 if (e
== '\'' || e
== '"' || (delim
&& e
== delim
) || e
== ESCAPE_META
|| (e
= unescape_char(*(ptr
+ 1))) != *(ptr
+ 1)) {
2713 if (*ptr
== '\'' && (inside_quotes
|| strchr(ptr
+1, '\''))) {
2714 if ((inside_quotes
= (1 - inside_quotes
))) {
2719 if (*ptr
!= ' ' || inside_quotes
) {
2732 SWITCH_DECLARE(unsigned int) switch_separate_string_string(char *buf
, char *delim
, char **array
, unsigned int arraylen
)
2734 unsigned int count
= 0;
2736 size_t dlen
= strlen(delim
);
2738 array
[count
++] = buf
;
2740 while (count
< arraylen
&& array
[count
- 1]) {
2741 if ((d
= strstr(array
[count
- 1], delim
))) {
2752 /* Separate a string using a delimiter that is not a space */
2753 static unsigned int separate_string_char_delim(char *buf
, char delim
, char **array
, unsigned int arraylen
)
2755 enum tokenizer_state
{
2760 unsigned int count
= 0;
2762 int inside_quotes
= 0;
2765 while (*ptr
&& count
< arraylen
) {
2768 array
[count
++] = ptr
;
2773 /* escaped characters are copied verbatim to the destination string */
2774 if (*ptr
== ESCAPE_META
) {
2776 } else if (*ptr
== '\'' && (inside_quotes
|| strchr(ptr
+1, '\''))) {
2777 inside_quotes
= (1 - inside_quotes
);
2778 } else if (*ptr
== delim
&& !inside_quotes
) {
2786 /* strip quotes, escaped chars and leading / trailing spaces */
2788 for (i
= 0; i
< count
; ++i
) {
2789 array
[i
] = cleanup_separated_string(array
[i
], delim
);
2795 /* Separate a string using a delimiter that is a space */
2796 static unsigned int separate_string_blank_delim(char *buf
, char **array
, unsigned int arraylen
)
2798 enum tokenizer_state
{
2805 unsigned int count
= 0;
2807 int inside_quotes
= 0;
2810 while (*ptr
&& count
< arraylen
) {
2813 array
[count
++] = ptr
;
2814 state
= SKIP_INITIAL_SPACE
;
2817 case SKIP_INITIAL_SPACE
:
2826 if (*ptr
== ESCAPE_META
) {
2828 } else if (*ptr
== '\'') {
2829 inside_quotes
= (1 - inside_quotes
);
2830 } else if (*ptr
== ' ' && !inside_quotes
) {
2832 state
= SKIP_ENDING_SPACE
;
2837 case SKIP_ENDING_SPACE
:
2846 /* strip quotes, escaped chars and leading / trailing spaces */
2848 for (i
= 0; i
< count
; ++i
) {
2849 array
[i
] = cleanup_separated_string(array
[i
], 0);
2855 SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf
, char delim
, char **array
, unsigned int arraylen
)
2857 if (!buf
|| !array
|| !arraylen
) {
2862 if (*buf
== '^' && *(buf
+1) == '^') {
2872 memset(array
, 0, arraylen
* sizeof(*array
));
2874 return (delim
== ' ' ? separate_string_blank_delim(buf
, array
, arraylen
) : separate_string_char_delim(buf
, delim
, array
, arraylen
));
2877 SWITCH_DECLARE(const char *) switch_cut_path(const char *in
)
2879 const char *p
, *ret
= in
;
2880 const char delims
[] = "/\\";
2884 for (i
= delims
; *i
; i
++) {
2886 while ((p
= strchr(p
, *i
)) != 0) {
2896 SWITCH_DECLARE(switch_status_t
) switch_string_match(const char *string
, size_t string_len
, const char *search
, size_t search_len
)
2900 for (i
= 0; (i
< search_len
) && (i
< string_len
); i
++) {
2901 if (string
[i
] != search
[i
]) {
2902 return SWITCH_STATUS_FALSE
;
2906 if (i
== search_len
) {
2907 return SWITCH_STATUS_SUCCESS
;
2910 return SWITCH_STATUS_FALSE
;
2913 SWITCH_DECLARE(char *) switch_string_replace(const char *string
, const char *search
, const char *replace
)
2915 size_t string_len
= strlen(string
);
2916 size_t search_len
= strlen(search
);
2917 size_t replace_len
= strlen(replace
);
2919 size_t dest_len
= 0;
2922 dest
= (char *) malloc(sizeof(char));
2923 switch_assert(dest
);
2925 for (i
= 0; i
< string_len
; i
++) {
2926 if (switch_string_match(string
+ i
, string_len
- i
, search
, search_len
) == SWITCH_STATUS_SUCCESS
) {
2927 for (n
= 0; n
< replace_len
; n
++) {
2928 dest
[dest_len
] = replace
[n
];
2930 tmp
= (char *) realloc(dest
, sizeof(char) * (dest_len
+ 1));
2934 i
+= search_len
- 1;
2936 dest
[dest_len
] = string
[i
];
2938 tmp
= (char *) realloc(dest
, sizeof(char) * (dest_len
+ 1));
2948 SWITCH_DECLARE(char *) switch_util_quote_shell_arg(const char *string
)
2950 return switch_util_quote_shell_arg_pool(string
, NULL
);
2953 SWITCH_DECLARE(char *) switch_util_quote_shell_arg_pool(const char *string
, switch_memory_pool_t
*pool
)
2955 size_t string_len
= strlen(string
);
2958 size_t dest_len
= 0;
2961 /* first pass through, figure out how large to make the allocation */
2962 dest_len
= strlen(string
) + 1; /* string + null */
2963 dest_len
+= 1; /* opening quote */
2964 for (i
= 0; i
< string_len
; i
++) {
2965 switch (string
[i
]) {
2968 /* We replace ' by sq backslace sq sq, so need 3 additional bytes */
2974 dest_len
+= 1; /* closing quote */
2976 /* if we're given a pool, allocate from it, otherwise use malloc */
2978 dest
= switch_core_alloc(pool
, sizeof(char) * dest_len
);
2980 dest
= (char *) malloc(sizeof(char) * dest_len
);
2982 switch_assert(dest
);
2990 for (i
= 0; i
< string_len
; i
++) {
2991 switch (string
[i
]) {
2999 /* We replace ' by sq backslash sq sq */
3007 dest
[n
++] = string
[i
];
3017 switch_assert(n
== dest_len
);
3025 SWITCH_DECLARE(int) switch_wait_sock(switch_os_socket_t sock
, uint32_t ms
, switch_poll_t flags
)
3027 struct pollfd pfds
[2] = { { 0 } };
3030 if (sock
== SWITCH_SOCK_INVALID
) {
3031 return SWITCH_SOCK_INVALID
;
3037 if ((flags
& SWITCH_POLL_READ
)) {
3038 pfds
[0].events
|= POLLIN
;
3041 if ((flags
& SWITCH_POLL_WRITE
)) {
3042 pfds
[0].events
|= POLLOUT
;
3045 if ((flags
& SWITCH_POLL_ERROR
)) {
3046 pfds
[0].events
|= POLLERR
;
3049 if ((flags
& SWITCH_POLL_HUP
)) {
3050 pfds
[0].events
|= POLLHUP
;
3053 if ((flags
& SWITCH_POLL_RDNORM
)) {
3054 pfds
[0].events
|= POLLRDNORM
;
3057 if ((flags
& SWITCH_POLL_RDBAND
)) {
3058 pfds
[0].events
|= POLLRDBAND
;
3061 if ((flags
& SWITCH_POLL_PRI
)) {
3062 pfds
[0].events
|= POLLPRI
;
3065 s
= poll(pfds
, 1, ms
);
3068 if (switch_errno_is_break(switch_errno())) {
3076 if ((pfds
[0].revents
& POLLIN
)) {
3077 r
|= SWITCH_POLL_READ
;
3079 if ((pfds
[0].revents
& POLLOUT
)) {
3080 r
|= SWITCH_POLL_WRITE
;
3082 if ((pfds
[0].revents
& POLLERR
)) {
3083 r
|= SWITCH_POLL_ERROR
;
3085 if ((pfds
[0].revents
& POLLHUP
)) {
3086 r
|= SWITCH_POLL_HUP
;
3088 if ((pfds
[0].revents
& POLLRDNORM
)) {
3089 r
|= SWITCH_POLL_RDNORM
;
3091 if ((pfds
[0].revents
& POLLRDBAND
)) {
3092 r
|= SWITCH_POLL_RDBAND
;
3094 if ((pfds
[0].revents
& POLLPRI
)) {
3095 r
|= SWITCH_POLL_PRI
;
3097 if ((pfds
[0].revents
& POLLNVAL
)) {
3098 r
|= SWITCH_POLL_INVALID
;
3106 SWITCH_DECLARE(int) switch_wait_socklist(switch_waitlist_t
*waitlist
, uint32_t len
, uint32_t ms
)
3108 struct pollfd
*pfds
;
3109 int s
= 0, r
= 0, i
;
3111 pfds
= calloc(len
, sizeof(struct pollfd
));
3112 switch_assert(pfds
);
3114 for (i
= 0; i
< len
; i
++) {
3115 if (waitlist
[i
].sock
== SWITCH_SOCK_INVALID
) {
3119 pfds
[i
].fd
= waitlist
[i
].sock
;
3121 if ((waitlist
[i
].events
& SWITCH_POLL_READ
)) {
3122 pfds
[i
].events
|= POLLIN
;
3125 if ((waitlist
[i
].events
& SWITCH_POLL_WRITE
)) {
3126 pfds
[i
].events
|= POLLOUT
;
3129 if ((waitlist
[i
].events
& SWITCH_POLL_ERROR
)) {
3130 pfds
[i
].events
|= POLLERR
;
3133 if ((waitlist
[i
].events
& SWITCH_POLL_HUP
)) {
3134 pfds
[i
].events
|= POLLHUP
;
3137 if ((waitlist
[i
].events
& SWITCH_POLL_RDNORM
)) {
3138 pfds
[i
].events
|= POLLRDNORM
;
3141 if ((waitlist
[i
].events
& SWITCH_POLL_RDBAND
)) {
3142 pfds
[i
].events
|= POLLRDBAND
;
3145 if ((waitlist
[i
].events
& SWITCH_POLL_PRI
)) {
3146 pfds
[i
].events
|= POLLPRI
;
3150 s
= poll(pfds
, len
, ms
);
3153 if (switch_errno_is_break(switch_errno())) {
3161 for (i
= 0; i
< len
; i
++) {
3162 if ((pfds
[i
].revents
& POLLIN
)) {
3163 r
|= SWITCH_POLL_READ
;
3164 waitlist
[i
].revents
|= SWITCH_POLL_READ
;
3166 if ((pfds
[i
].revents
& POLLOUT
)) {
3167 r
|= SWITCH_POLL_WRITE
;
3168 waitlist
[i
].revents
|= SWITCH_POLL_WRITE
;
3170 if ((pfds
[i
].revents
& POLLERR
)) {
3171 r
|= SWITCH_POLL_ERROR
;
3172 waitlist
[i
].revents
|= SWITCH_POLL_ERROR
;
3174 if ((pfds
[i
].revents
& POLLHUP
)) {
3175 r
|= SWITCH_POLL_HUP
;
3176 waitlist
[i
].revents
|= SWITCH_POLL_HUP
;
3178 if ((pfds
[i
].revents
& POLLRDNORM
)) {
3179 r
|= SWITCH_POLL_RDNORM
;
3180 waitlist
[i
].revents
|= SWITCH_POLL_RDNORM
;
3182 if ((pfds
[i
].revents
& POLLRDBAND
)) {
3183 r
|= SWITCH_POLL_RDBAND
;
3184 waitlist
[i
].revents
|= SWITCH_POLL_RDBAND
;
3186 if ((pfds
[i
].revents
& POLLPRI
)) {
3187 r
|= SWITCH_POLL_PRI
;
3188 waitlist
[i
].revents
|= SWITCH_POLL_PRI
;
3190 if ((pfds
[i
].revents
& POLLNVAL
)) {
3191 r
|= SWITCH_POLL_INVALID
;
3192 waitlist
[i
].revents
|= SWITCH_POLL_INVALID
;
3204 /* use select instead of poll */
3205 SWITCH_DECLARE(int) switch_wait_sock(switch_os_socket_t sock
, uint32_t ms
, switch_poll_t flags
)
3213 if (sock
== SWITCH_SOCK_INVALID
) {
3214 return SWITCH_SOCK_INVALID
;
3217 rfds
= malloc(sizeof(fd_set
));
3218 wfds
= malloc(sizeof(fd_set
));
3219 efds
= malloc(sizeof(fd_set
));
3226 /* Wouldn't you rather know?? */
3227 assert(sock
<= FD_SETSIZE
);
3230 if ((flags
& SWITCH_POLL_READ
)) {
3233 #pragma warning( push )
3234 #pragma warning( disable : 4127 )
3236 #pragma warning( pop )
3242 if ((flags
& SWITCH_POLL_WRITE
)) {
3245 #pragma warning( push )
3246 #pragma warning( disable : 4127 )
3248 #pragma warning( pop )
3254 if ((flags
& SWITCH_POLL_ERROR
)) {
3257 #pragma warning( push )
3258 #pragma warning( disable : 4127 )
3260 #pragma warning( pop )
3266 tv
.tv_sec
= ms
/ 1000;
3267 tv
.tv_usec
= (ms
% 1000) * 1000;
3269 s
= select(sock
+ 1, (flags
& SWITCH_POLL_READ
) ? rfds
: NULL
, (flags
& SWITCH_POLL_WRITE
) ? wfds
: NULL
, (flags
& SWITCH_POLL_ERROR
) ? efds
: NULL
, &tv
);
3272 if (switch_errno_is_break(switch_errno())) {
3280 if ((flags
& SWITCH_POLL_READ
) && FD_ISSET(sock
, rfds
)) {
3281 r
|= SWITCH_POLL_READ
;
3284 if ((flags
& SWITCH_POLL_WRITE
) && FD_ISSET(sock
, wfds
)) {
3285 r
|= SWITCH_POLL_WRITE
;
3288 if ((flags
& SWITCH_POLL_ERROR
) && FD_ISSET(sock
, efds
)) {
3289 r
|= SWITCH_POLL_ERROR
;
3301 SWITCH_DECLARE(int) switch_wait_socklist(switch_waitlist_t
*waitlist
, uint32_t len
, uint32_t ms
)
3309 switch_os_socket_t max_fd
= 0;
3312 rfds
= malloc(sizeof(fd_set
));
3313 wfds
= malloc(sizeof(fd_set
));
3314 efds
= malloc(sizeof(fd_set
));
3320 for (i
= 0; i
< len
; i
++) {
3321 if (waitlist
[i
].sock
== SWITCH_SOCK_INVALID
) {
3325 if (waitlist
[i
].sock
> max_fd
) {
3326 max_fd
= waitlist
[i
].sock
;
3330 /* Wouldn't you rather know?? */
3331 assert(waitlist
[i
].sock
<= FD_SETSIZE
);
3333 flags
|= waitlist
[i
].events
;
3335 if ((waitlist
[i
].events
& SWITCH_POLL_READ
)) {
3338 #pragma warning( push )
3339 #pragma warning( disable : 4127 )
3340 FD_SET(waitlist
[i
].sock
, rfds
);
3341 #pragma warning( pop )
3343 FD_SET(waitlist
[i
].sock
, rfds
);
3347 if ((waitlist
[i
].events
& SWITCH_POLL_WRITE
)) {
3350 #pragma warning( push )
3351 #pragma warning( disable : 4127 )
3352 FD_SET(waitlist
[i
].sock
, wfds
);
3353 #pragma warning( pop )
3355 FD_SET(waitlist
[i
].sock
, wfds
);
3359 if ((waitlist
[i
].events
& SWITCH_POLL_ERROR
)) {
3362 #pragma warning( push )
3363 #pragma warning( disable : 4127 )
3364 FD_SET(waitlist
[i
].sock
, efds
);
3365 #pragma warning( pop )
3367 FD_SET(waitlist
[i
].sock
, efds
);
3372 tv
.tv_sec
= ms
/ 1000;
3373 tv
.tv_usec
= (ms
% 1000) * 1000;
3375 s
= select(max_fd
+ 1, (flags
& SWITCH_POLL_READ
) ? rfds
: NULL
, (flags
& SWITCH_POLL_WRITE
) ? wfds
: NULL
, (flags
& SWITCH_POLL_ERROR
) ? efds
: NULL
, &tv
);
3378 if (switch_errno_is_break(switch_errno())) {
3386 for (i
= 0; i
< len
; i
++) {
3387 if ((waitlist
[i
].events
& SWITCH_POLL_READ
) && FD_ISSET(waitlist
[i
].sock
, rfds
)) {
3388 r
|= SWITCH_POLL_READ
;
3389 waitlist
[i
].revents
|= SWITCH_POLL_READ
;
3392 if ((waitlist
[i
].events
& SWITCH_POLL_WRITE
) && FD_ISSET(waitlist
[i
].sock
, wfds
)) {
3393 r
|= SWITCH_POLL_WRITE
;
3394 waitlist
[i
].revents
|= SWITCH_POLL_WRITE
;
3397 if ((waitlist
[i
].events
& SWITCH_POLL_ERROR
) && FD_ISSET(waitlist
[i
].sock
, efds
)) {
3398 r
|= SWITCH_POLL_ERROR
;
3399 waitlist
[i
].revents
|= SWITCH_POLL_ERROR
;
3413 SWITCH_DECLARE(int) switch_socket_waitfor(switch_pollfd_t
*poll
, int ms
)
3417 switch_poll(poll
, 1, &nsds
, ms
);
3422 SWITCH_DECLARE(char *) switch_core_session_url_encode(switch_core_session_t
*session
, const char *url
)
3424 return switch_core_url_encode_opt(switch_core_session_get_pool(session
), url
, SWITCH_FALSE
);
3427 SWITCH_DECLARE(char *) switch_core_session_url_encode_opt(switch_core_session_t
*session
, const char *url
, switch_bool_t double_encode
)
3429 return switch_core_url_encode_opt(switch_core_session_get_pool(session
), url
, double_encode
);
3432 SWITCH_DECLARE(char *) switch_core_url_encode(switch_memory_pool_t
*pool
, const char *url
)
3434 return switch_core_url_encode_opt(pool
, url
, SWITCH_FALSE
);
3437 SWITCH_DECLARE(char *) switch_core_url_encode_opt(switch_memory_pool_t
*pool
, const char *url
, switch_bool_t double_encode
)
3439 const char hex
[] = "0123456789ABCDEF";
3440 switch_size_t len
= 0;
3441 switch_size_t slen
= 0;
3444 if (!url
) return NULL
;
3445 if (!pool
) return NULL
;
3449 for (p
= url
; *p
; p
++) {
3455 if (!double_encode
&& *p
== '%' && e
-p
> 1) {
3456 if (strchr(hex
, *(p
+1)) && strchr(hex
, *(p
+2))) {
3461 if (!ok
&& (*p
< ' ' || *p
> '~' || strchr(SWITCH_URL_UNSAFE
, *p
))) {
3467 len
++; /* NULL Terminatior */
3470 return switch_core_strdup(pool
, url
);
3472 return switch_url_encode_opt(url
, switch_core_alloc(pool
, sizeof(char) * len
), len
, double_encode
);
3476 SWITCH_DECLARE(char *) switch_url_encode_opt(const char *url
, char *buf
, size_t len
, switch_bool_t double_encode
)
3478 const char *p
, *e
= end_of_p(url
);
3480 const char hex
[] = "0123456789ABCDEF";
3492 for (p
= url
; *p
; p
++) {
3499 if (!double_encode
&& *p
== '%' && e
-p
> 1) {
3500 if (strchr(hex
, *(p
+1)) && strchr(hex
, *(p
+2))) {
3505 if (!ok
&& (*p
< ' ' || *p
> '~' || strchr(SWITCH_URL_UNSAFE
, *p
))) {
3506 if ((x
+ 3) > len
) {
3510 buf
[x
++] = hex
[(*p
>> 4) & 0x0f];
3511 buf
[x
++] = hex
[*p
& 0x0f];
3521 SWITCH_DECLARE(char *) switch_url_encode(const char *url
, char *buf
, size_t len
)
3523 return switch_url_encode_opt(url
, buf
, len
, SWITCH_FALSE
);
3526 SWITCH_DECLARE(char *) switch_url_decode(char *s
)
3531 if (zstr(s
) || !strchr(s
, '%')) {
3535 for (o
= s
; *s
; s
++, o
++) {
3536 if (*s
== '%' && strlen(s
) > 2 && sscanf(s
+ 1, "%2x", &tmp
) == 1) {
3547 SWITCH_DECLARE(void) switch_split_time(const char *exp
, int *hour
, int *min
, int *sec
)
3549 char *dup
= strdup(exp
);
3557 if ((smin
=strchr(dup
, ':'))) {
3559 if ((ssec
=strchr(smin
, ':'))) {
3565 *hour
= atol(shour
);
3575 switch_safe_free(dup
);
3580 SWITCH_DECLARE(void) switch_split_date(const char *exp
, int *year
, int *month
, int *day
)
3582 char *dup
= strdup(exp
);
3584 char *smonth
= NULL
;
3590 if ((smonth
=strchr(dup
, '-'))) {
3592 if ((sday
=strchr(smonth
, '-'))) {
3595 *year
= atol(syear
);
3598 *month
= atol(smonth
);
3605 switch_safe_free(dup
);
3610 /* Ex exp value "2009-10-10 14:33:22~2009-11-10 17:32:31" */
3611 SWITCH_DECLARE(int) switch_fulldate_cmp(const char *exp
, switch_time_t
*ts
)
3613 char *dup
= strdup(exp
);
3618 switch_time_t tsStart
= 0;
3619 switch_time_t tsEnd
= 0;
3625 if ((p
= strchr(cur
, ','))) {
3631 if ((sEnd
= strchr(cur
, '~'))) {
3634 tsStart
= switch_str_time(sStart
);
3635 tsEnd
= switch_str_time(sEnd
);
3638 if (tsStart
== 0 || tsEnd
== 0) {
3639 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Parse error for date time range (%s~%s)\n", sStart
, sEnd
);
3643 if (tsStart
<= *ts
&& tsEnd
> *ts
) {
3650 if ((p
= strchr(p
, ','))) {
3656 switch_safe_free(dup
);
3661 /* Written by Marc Espie, public domain */
3662 #define SWITCH_CTYPE_NUM_CHARS 256
3664 const short _switch_C_toupper_
[1 + SWITCH_CTYPE_NUM_CHARS
] = {
3666 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
3667 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
3668 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3669 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3670 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3671 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3672 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3673 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3674 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
3675 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
3676 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
3677 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3678 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
3679 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
3680 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
3681 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3682 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3683 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3684 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3685 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3686 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3687 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3688 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3689 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3690 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3691 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3692 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3693 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3694 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3695 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3696 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3697 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3700 const short *_switch_toupper_tab_
= _switch_C_toupper_
;
3702 SWITCH_DECLARE(int) old_switch_toupper(int c
)
3704 if ((unsigned int) c
> 255)
3708 return ((_switch_toupper_tab_
+ 1)[c
]);
3711 const short _switch_C_tolower_
[1 + SWITCH_CTYPE_NUM_CHARS
] = {
3713 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
3714 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
3715 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
3716 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
3717 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
3718 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
3719 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
3720 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
3721 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3722 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3723 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3724 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
3725 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
3726 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
3727 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
3728 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
3729 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3730 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3731 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3732 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
3733 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
3734 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
3735 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
3736 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
3737 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
3738 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
3739 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
3740 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
3741 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
3742 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
3743 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
3744 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
3747 const short *_switch_tolower_tab_
= _switch_C_tolower_
;
3749 SWITCH_DECLARE(int) old_switch_tolower(int c
)
3751 if ((unsigned int) c
> 255)
3755 return ((_switch_tolower_tab_
+ 1)[c
]);
3759 * Copyright (c) 1989 The Regents of the University of California.
3760 * All rights reserved.
3761 * (c) UNIX System Laboratories, Inc.
3762 * All or some portions of this file are derived from material licensed
3763 * to the University of California by American Telephone and Telegraph
3764 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
3765 * the permission of UNIX System Laboratories, Inc.
3767 * Redistribution and use in source and binary forms, with or without
3768 * modification, are permitted provided that the following conditions
3770 * 1. Redistributions of source code must retain the above copyright
3771 * notice, this list of conditions and the following disclaimer.
3772 * 2. Redistributions in binary form must reproduce the above copyright
3773 * notice, this list of conditions and the following disclaimer in the
3774 * documentation and/or other materials provided with the distribution.
3775 * 3. Neither the name of the University nor the names of its contributors
3776 * may be used to endorse or promote products derived from this software
3777 * without specific prior written permission.
3779 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3780 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3781 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3782 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3783 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3784 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3785 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3786 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3787 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3788 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3810 const int _switch_C_ctype_
[1 + SWITCH_CTYPE_NUM_CHARS
] = {
3812 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
,
3813 _C
, _C
| _S
, _C
| _S
, _C
| _S
, _C
| _S
, _C
| _S
, _C
, _C
,
3814 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
,
3815 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
,
3816 _S
| _B
, _P
, _P
, _P
, _P
, _P
, _P
, _P
,
3817 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
,
3818 _N
, _N
, _N
, _N
, _N
, _N
, _N
, _N
,
3819 _N
, _N
, _P
, _P
, _P
, _P
, _P
, _P
,
3820 _P
, _U
| _X
, _U
| _X
, _U
| _X
, _U
| _X
, _U
| _X
, _U
| _X
, _U
,
3821 _U
, _U
, _U
, _U
, _U
, _U
, _U
, _U
,
3822 _U
, _U
, _U
, _U
, _U
, _U
, _U
, _U
,
3823 _U
, _U
, _U
, _P
, _P
, _P
, _P
, _P
,
3824 _P
, _L
| _X
, _L
| _X
, _L
| _X
, _L
| _X
, _L
| _X
, _L
| _X
, _L
,
3825 _L
, _L
, _L
, _L
, _L
, _L
, _L
, _L
,
3826 _L
, _L
, _L
, _L
, _L
, _L
, _L
, _L
,
3827 /* determine printability based on the IS0 8859 8-bit standard */
3828 _L
, _L
, _L
, _P
, _P
, _P
, _P
, _C
,
3830 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
, /* 80 */
3831 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
, /* 88 */
3832 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
, /* 90 */
3833 _C
, _C
, _C
, _C
, _C
, _C
, _C
, _C
, /* 98 */
3834 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* A0 */
3835 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* A8 */
3836 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* B0 */
3837 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* B8 */
3838 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* C0 */
3839 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* C8 */
3840 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* D0 */
3841 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* D8 */
3842 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* E0 */
3843 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* E8 */
3844 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
, /* F0 */
3845 _P
, _P
, _P
, _P
, _P
, _P
, _P
, _P
/* F8 */
3848 const int *_switch_ctype_
= _switch_C_ctype_
;
3850 SWITCH_DECLARE(int) switch_isalnum(int c
)
3852 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & (_U
| _L
| _N
)));
3855 SWITCH_DECLARE(int) switch_isalpha(int c
)
3857 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & (_U
| _L
)));
3860 SWITCH_DECLARE(int) switch_iscntrl(int c
)
3862 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _C
));
3865 SWITCH_DECLARE(int) switch_isdigit(int c
)
3867 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _N
));
3870 SWITCH_DECLARE(int) switch_isgraph(int c
)
3872 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & (_P
| _U
| _L
| _N
)));
3875 SWITCH_DECLARE(int) switch_islower(int c
)
3877 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _L
));
3880 SWITCH_DECLARE(int) switch_isprint(int c
)
3882 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & (_P
| _U
| _L
| _N
| _B
)));
3885 SWITCH_DECLARE(int) switch_ispunct(int c
)
3887 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _P
));
3890 SWITCH_DECLARE(int) switch_isspace(int c
)
3892 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _S
));
3895 SWITCH_DECLARE(int) switch_isupper(int c
)
3897 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & _U
));
3900 SWITCH_DECLARE(int) switch_isxdigit(int c
)
3902 return (c
< 0 ? 0 : c
> 255 ? 0 : ((_switch_ctype_
+ 1)[(unsigned char) c
] & (_N
| _X
)));
3904 static const char *DOW
[] = {
3914 SWITCH_DECLARE(const char *) switch_dow_int2str(int val
) {
3915 if (val
>= switch_arraylen(DOW
)) {
3916 val
= val
% switch_arraylen(DOW
);
3921 SWITCH_DECLARE(int) switch_dow_str2int(const char *exp
) {
3925 for (x
= 0; x
< switch_arraylen(DOW
); x
++) {
3926 if (!strncasecmp(DOW
[x
], exp
, 3)) {
3948 static inline dow_t
_dow_read_token(const char **s
)
3955 } else if (**s
== ',') {
3958 } else if (**s
>= '1' && **s
<= '7') {
3959 dow_t r
= **s
- '0';
3962 } else if ((i
= switch_dow_str2int(*s
)) && i
!= -1) {
3972 SWITCH_DECLARE(switch_bool_t
) switch_dow_cmp(const char *exp
, int val
)
3974 dow_t cur
, prev
= DOW_EOF
, range_start
= DOW_EOF
;
3975 const char *p
= exp
;
3977 while ((cur
= _dow_read_token(&p
)) != DOW_EOF
) {
3978 if (cur
== DOW_COMA
) {
3981 } else if (cur
== DOW_HYPHEN
) {
3982 /* Save the previous token and move to the next one */
3984 } else if (cur
== DOW_ERR
) {
3985 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Parse error for [%s] at position %ld (%.6s)\n", exp
, (long) (p
- exp
), p
);
3988 /* Valid day found */
3989 if (range_start
!= DOW_EOF
) { /* Evaluating a range */
3990 if (range_start
<= cur
? (val
>= range_start
&& val
<= cur
) : (val
>= range_start
|| val
<= cur
)) {
3993 range_start
= DOW_EOF
;
3994 } else if (val
== cur
) {
4002 return SWITCH_FALSE
;
4005 SWITCH_DECLARE(int) switch_number_cmp(const char *exp
, int val
)
4007 // Expression exp must be a comma separated list of numbers or ranges.
4008 // To match numbers not in range 9-17, enter the reversed range 18-8.
4010 int a
= strtol(exp
, (char **)&exp
, 10);
4015 int b
= strtol(++exp
, (char **)&exp
, 10);
4016 if (a
<= b
? (val
>= a
&& val
<=b
) : (val
>= a
|| val
<= b
))
4024 SWITCH_DECLARE(int) switch_tod_cmp(const char *exp
, int val
)
4026 char *dup
= strdup(exp
);
4035 int range_start
, range_end
;
4040 if ((p
= strchr(cur
, ','))) {
4046 if ((minm
=strchr(cur
, ':'))) {
4048 if ((maxh
=strchr(minm
, '-'))) {
4049 if ((maxm
=strchr(maxh
, ':'))) {
4052 /* Check if min/max seconds are present */
4053 if ((mins
=strchr(minm
, ':'))) {
4058 if ((maxs
=strchr(maxm
, ':'))) {
4064 range_start
= (atol(minh
) * 60 * 60) + (atol(minm
) * 60) + atol(mins
);
4065 range_end
= (atol(maxh
) * 60 * 60) + (atol(maxm
) * 60) + atol(maxs
);
4066 if (range_start
<= range_end
? (val
>= range_start
&& val
<= range_end
) : (val
>= range_start
|| val
<= range_end
)) {
4067 switch_safe_free(dup
);
4076 if ((p
= strchr(p
, ','))) {
4083 switch_safe_free(dup
);
4088 SWITCH_DECLARE(int) switch_split_user_domain(char *in
, char **user
, char **domain
)
4090 char *p
= NULL
, *h
= NULL
, *u
= NULL
;
4094 /* Remove URL scheme */
4095 if (!strncasecmp(in
, "sip:", 4)) in
+= 4;
4096 else if (!strncasecmp(in
, "sips:", 5)) in
+= 5;
4098 /* Isolate the host part from the user part */
4099 if ((h
= in
, p
= strchr(h
, '@'))) *p
= '\0', u
= in
, h
= p
+1;
4101 /* Clean out the host part of any suffix */
4102 for (p
= h
; *p
; p
++)
4103 if (*p
== ':' || *p
== ';' || *p
== ' ') {
4107 if (user
) *user
= u
;
4108 if (domain
) *domain
= h
;
4113 SWITCH_DECLARE(char *) switch_uuid_str(char *buf
, switch_size_t len
)
4117 if (len
< (SWITCH_UUID_FORMATTED_LENGTH
+ 1)) {
4118 switch_snprintf(buf
, len
, "INVALID");
4120 switch_uuid_get(&uuid
);
4121 switch_uuid_format(buf
, &uuid
);
4128 SWITCH_DECLARE(char *) switch_format_number(const char *num
)
4132 const char *p
= num
;
4146 if (!switch_is_number(p
)) {
4152 /* region 1, TBD add more....*/
4153 if (len
== 11 && p
[0] == '1') {
4154 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]);
4155 } else if (len
== 10) {
4156 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]);
4165 SWITCH_DECLARE(unsigned int) switch_atoui(const char *nptr
)
4167 int tmp
= atoi(nptr
);
4168 if (tmp
< 0) return 0;
4169 else return (unsigned int) tmp
;
4172 SWITCH_DECLARE(unsigned long) switch_atoul(const char *nptr
)
4174 long tmp
= atol(nptr
);
4175 if (tmp
< 0) return 0;
4176 else return (unsigned long) tmp
;
4180 SWITCH_DECLARE(char *) switch_strerror_r(int errnum
, char *buf
, switch_size_t buflen
)
4182 #ifdef HAVE_STRERROR_R
4183 #ifdef STRERROR_R_CHAR_P
4184 /* GNU variant returning char *, avoids warn-unused-result error */
4185 return strerror_r(errnum
, buf
, buflen
);
4188 * XSI variant returning int, with GNU compatible error string,
4189 * if no message could be found
4191 if (strerror_r(errnum
, buf
, buflen
)) {
4192 switch_snprintf(buf
, buflen
, "Unknown error %d", errnum
);
4195 #endif /* STRERROR_R_CHAR_P */
4196 #elif defined(WIN32)
4198 if (strerror_s(buf
, buflen
, errnum
)) {
4199 switch_snprintf(buf
, buflen
, "Unknown error %d", errnum
);
4203 /* Fallback, copy string into private buffer */
4204 switch_copy_string(buf
, strerror(errnum
), buflen
);
4209 SWITCH_DECLARE(void) switch_http_parse_qs(switch_http_request_t
*request
, char *qs
)
4218 } else { /*parse our own qs, dup to avoid modify the original string */
4219 dup
= q
= strdup(request
->qs
);
4228 if ((next
= strchr(next
, '&'))) {
4232 for (p
= q
; p
&& *p
; p
++) {
4233 if (*p
== '+') *p
= ' ';
4236 switch_url_decode(q
);
4239 if ((val
= strchr(name
, '='))) {
4241 switch_event_add_header_string(request
->headers
, SWITCH_STACK_BOTTOM
, name
, val
);
4246 switch_safe_free(dup
);
4249 /* clean the uri to protect us from vulnerability attack */
4250 switch_status_t
clean_uri(char *uri
)
4254 int last
, i
, len
, uri_len
= 0;
4256 argc
= switch_separate_string(uri
, '/', argv
, sizeof(argv
) / sizeof(argv
[0]));
4258 if (argc
== sizeof(argv
)) { /* too deep */
4259 return SWITCH_STATUS_FALSE
;
4263 for(i
= 1; i
< argc
; i
++) {
4264 if (*argv
[i
] == '\0' || !strcmp(argv
[i
], ".")) {
4265 /* ignore //// or /././././ */
4266 } else if (!strcmp(argv
[i
], "..")) {
4267 /* got /../, go up one level */
4268 if (last
> 1) last
--;
4270 argv
[last
++] = argv
[i
];
4274 for(i
= 1; i
< last
; i
++) {
4275 len
= strlen(argv
[i
]);
4276 sprintf(uri
+ uri_len
, "/%s", argv
[i
]);
4277 uri_len
+= (len
+ 1);
4280 return SWITCH_STATUS_SUCCESS
;
4283 SWITCH_DECLARE(switch_status_t
) switch_http_parse_header(char *buffer
, uint32_t datalen
, switch_http_request_t
*request
)
4285 switch_status_t status
= SWITCH_STATUS_FALSE
;
4290 char *headers
[64] = { 0 };
4292 char *argv
[2] = { 0 };
4295 if (datalen
< 16) return status
; /* minimum GET / HTTP/1.1\r\n */
4297 while(i
--) { // sanity check
4298 if (*p
++ == ' ') break;
4301 if (i
== 0) return status
;
4303 if ((body
= strstr(buffer
, "\r\n\r\n"))) {
4306 } else if (( body
= strstr(buffer
, "\n\n"))) {
4313 request
->_buffer
= strdup(buffer
);
4314 switch_assert(request
->_buffer
);
4315 request
->method
= request
->_buffer
;
4316 request
->bytes_buffered
= datalen
;
4317 request
->bytes_header
= body
- buffer
;
4318 request
->bytes_read
= body
- buffer
;
4320 p
= strchr(request
->method
, ' ');
4326 if (*p
!= '/') goto err
; /* must start from '/' */
4329 p
= strchr(request
->uri
, ' ');
4336 p
= strchr(request
->uri
, '?');
4343 if (clean_uri((char *)request
->uri
) != SWITCH_STATUS_SUCCESS
) {
4347 if (!strncmp(http
, "HTTP/1.1", 8)) {
4348 request
->keepalive
= SWITCH_TRUE
;
4349 } else if (strncmp(http
, "HTTP/1.0", 8)) {
4353 if (!request
->headers
) {
4354 if (switch_event_create(&request
->headers
, SWITCH_EVENT_CHANNEL_DATA
) != SWITCH_STATUS_SUCCESS
) {
4357 request
->_destroy_headers
= SWITCH_TRUE
;
4360 p
= strchr(http
, '\n');
4363 *p
++ = '\0'; // now the first header
4368 header_count
= switch_separate_string(p
, '\n', headers
, sizeof(headers
)/ sizeof(headers
[0]));
4370 if (header_count
< 1) goto err
;
4372 for (i
= 0; i
< header_count
; i
++) {
4373 char *header
, *value
;
4376 argc
= switch_separate_string(headers
[i
], ':', argv
, 2);
4378 if (argc
!= 2) goto err
;
4383 if (*value
== ' ') value
++;
4385 len
= strlen(value
);
4387 if (len
&& *(value
+ len
- 1) == '\r') *(value
+ len
- 1) = '\0';
4389 switch_event_add_header_string(request
->headers
, SWITCH_STACK_BOTTOM
, header
, value
);
4391 if (!strncasecmp(header
, "User-Agent", 10)) {
4392 request
->user_agent
= value
;
4393 } else if (!strncasecmp(header
, "Host", 4)) {
4394 request
->host
= value
;
4395 p
= strchr(value
, ':');
4400 if (*p
) request
->port
= (switch_port_t
)atoi(p
);
4402 } else if (!strncasecmp(header
, "Content-Type", 12)) {
4403 request
->content_type
= value
;
4404 } else if (!strncasecmp(header
, "Content-Length", 14)) {
4405 request
->content_length
= atoi(value
);
4406 } else if (!strncasecmp(header
, "Referer", 7)) {
4407 request
->referer
= value
;
4414 switch_http_parse_qs(request
, NULL
);
4417 return SWITCH_STATUS_SUCCESS
;
4420 switch_http_free_request(request
);
4424 SWITCH_DECLARE(void) switch_http_free_request(switch_http_request_t
*request
)
4426 if (request
->_buffer
) free(request
->_buffer
);
4427 if (request
->_destroy_headers
&& request
->headers
) {
4428 switch_event_destroy(&request
->headers
);
4432 /* for debugging only */
4433 SWITCH_DECLARE(void) switch_http_dump_request(switch_http_request_t
*request
)
4435 switch_assert(request
->method
);
4437 printf("method: %s\n", request
->method
);
4439 if (request
->uri
) printf("uri: %s\n", request
->uri
);
4440 if (request
->qs
) printf("qs: %s\n", request
->qs
);
4441 if (request
->host
) printf("host: %s\n", request
->host
);
4442 if (request
->port
) printf("port: %d\n", request
->port
);
4443 if (request
->from
) printf("from: %s\n", request
->from
);
4444 if (request
->user_agent
) printf("user_agent: %s\n", request
->user_agent
);
4445 if (request
->referer
) printf("referer: %s\n", request
->referer
);
4446 if (request
->user
) printf("user: %s\n", request
->user
);
4447 if (request
->keepalive
) printf("uri: %d\n", request
->keepalive
);
4448 if (request
->content_type
) printf("uri: %s\n", request
->content_type
);
4449 if (request
->content_length
) printf("uri: %" SWITCH_SIZE_T_FMT
"\n", request
->content_length
);
4452 switch_event_header_t
*header
= request
->headers
->headers
;
4454 printf("headers:\n-------------------------\n");
4457 printf("%s: %s\n", header
->name
, header
->value
);
4458 header
= header
->next
;
4463 SWITCH_DECLARE(void) switch_getcputime(switch_cputime
*t
)
4466 FILETIME ct
, et
, kt
, ut
; // Times are in 100-ns ticks (div 10000 to get ms)
4467 GetProcessTimes(GetCurrentProcess(), &ct
, &et
, &kt
, &ut
);
4468 t
->userms
= ((int64_t)ut
.dwLowDateTime
| ((int64_t)ut
.dwHighDateTime
<< 32)) / 10000;
4469 t
->kernelms
= ((int64_t)kt
.dwLowDateTime
| ((int64_t)kt
.dwHighDateTime
<< 32)) / 10000;
4470 #elif defined(HAVE_GETRUSAGE)
4472 getrusage(RUSAGE_SELF
, &r
);
4473 t
->userms
= r
.ru_utime
.tv_sec
* 1000 + r
.ru_utime
.tv_usec
/ 1000;
4474 t
->kernelms
= r
.ru_stime
.tv_sec
* 1000 + r
.ru_stime
.tv_usec
/ 1000;
4482 #ifdef SWITCH_HAVE_GUMBO
4483 static void process(GumboNode
*node
, switch_stream_handle_t
*stream
)
4485 if (node
->type
== GUMBO_NODE_TEXT
) {
4486 stream
->write_function(stream
, "%s", node
->v
.text
.text
);
4488 } else if (node
->type
== GUMBO_NODE_ELEMENT
&& node
->v
.element
.tag
!= GUMBO_TAG_SCRIPT
&& node
->v
.element
.tag
!= GUMBO_TAG_STYLE
) {
4489 GumboVector
*children
= &node
->v
.element
.children
;
4492 if (node
->v
.element
.tag
!= GUMBO_TAG_UNKNOWN
&& node
->v
.element
.tag
<= GUMBO_TAG_LAST
) {
4493 GumboAttribute
* attr
= NULL
;
4494 const char *aval
= NULL
;
4496 if (node
->v
.element
.tag
== GUMBO_TAG_SPAN
) {
4497 if ((attr
= gumbo_get_attribute(&node
->v
.element
.attributes
, "class"))) {
4502 if (aval
&& !strcasecmp(aval
, "Apple-converted-space")) {
4503 const char *txt
= ((GumboNode
*)children
->data
[0])->v
.text
.text
;
4506 for (x
= 0; txt
[x
]; x
++) {
4507 if (txt
[x
] == ' ') {
4512 for (x
= 0; x
< len
*2; x
++) {
4513 stream
->write_function(stream
, "%s", " ");
4516 for (i
= 0; i
< children
->length
; ++i
) {
4517 process((GumboNode
*) children
->data
[i
], stream
);
4521 if (node
->v
.element
.tag
== GUMBO_TAG_P
|| node
->v
.element
.tag
== GUMBO_TAG_BR
) {
4522 stream
->write_function(stream
, "%s", "\n");
4530 SWITCH_DECLARE(char *)switch_html_strip(const char *str
)
4532 char *p
, *html
= NULL
, *text
= NULL
;
4533 int x
= 0, got_ct
= 0;
4534 #ifdef SWITCH_HAVE_GUMBO
4535 GumboOutput
*output
;
4536 switch_stream_handle_t stream
;
4538 SWITCH_STANDARD_STREAM(stream
);
4541 for(p
= (char *)str
; p
&& *p
; p
++) {
4543 if (!strncasecmp(p
, "Content-Type:", 13)) {
4547 if (!got_ct
) continue;
4554 } else if (x
&& (*p
!= '\r')) {
4561 #ifdef SWITCH_HAVE_GUMBO
4562 if ((output
= gumbo_parse_with_options(&kGumboDefaultOptions
, html
, strlen(html
)))) {
4563 process(output
->root
, &stream
);
4564 gumbo_destroy_output(&kGumboDefaultOptions
, output
);
4567 text
= (char *)stream
.data
;
4569 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_WARNING
, "Support for html parser is not compiled.\n");
4570 text
= switch_safe_strdup(html
);
4576 SWITCH_DECLARE(unsigned long) switch_getpid(void)
4579 pid_t pid
= getpid();
4581 int pid
= _getpid();
4584 return (unsigned long)pid
;
4587 SWITCH_DECLARE(switch_status_t
) switch_digest(const char *digest_name
, unsigned char **digest
, const void *input
, switch_size_t inputLen
, unsigned int *outputlen
)
4589 #if defined(HAVE_OPENSSL)
4594 switch_assert(digest
);
4597 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Message digest is not set\n");
4598 return SWITCH_STATUS_FALSE
;
4601 md
= EVP_get_digestbyname(digest_name
);
4604 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Unknown message digest %s\n", digest_name
);
4605 return SWITCH_STATUS_FALSE
;
4608 size
= EVP_MD_size(md
);
4609 if (!size
|| !(*digest
= malloc(size
))) {
4610 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "Zero digest size or can't allocate memory to store results %s\n", digest_name
);
4611 return SWITCH_STATUS_FALSE
;
4614 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
4615 mdctx
= EVP_MD_CTX_new();
4617 mdctx
= EVP_MD_CTX_create();
4621 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "EVP_MD_CTX_new error\n");
4622 switch_safe_free(*digest
);
4623 return SWITCH_STATUS_FALSE
;
4626 EVP_MD_CTX_init(mdctx
);
4627 EVP_DigestInit_ex(mdctx
, md
, NULL
);
4628 EVP_DigestUpdate(mdctx
, input
, inputLen
);
4629 EVP_DigestFinal_ex(mdctx
, *digest
, outputlen
);
4631 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
4632 EVP_MD_CTX_free(mdctx
);
4634 EVP_MD_CTX_destroy(mdctx
);
4637 return SWITCH_STATUS_SUCCESS
;
4639 return SWITCH_STATUS_FALSE
;
4643 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
)
4645 unsigned char *digest
= NULL
;
4646 switch_status_t status
;
4650 status
= switch_digest(digest_name
, &digest
, input
, inputLen
, outputlen
);
4652 if (status
== SWITCH_STATUS_SUCCESS
) {
4653 if ((*digest_str
= malloc(*outputlen
* 2 + 1))) {
4654 for (x
= i
= 0; x
< *outputlen
; x
++) {
4655 b
= (digest
[x
] >> 4) & 15;
4656 (*digest_str
)[i
++] = b
+ (b
> 9 ? 'a' - 10 : '0');
4658 (*digest_str
)[i
++] = b
+ (b
> 9 ? 'a' - 10 : '0');
4661 (*digest_str
)[i
] = '\0';
4663 switch_safe_free(digest
);
4665 return SWITCH_STATUS_FALSE
;
4669 switch_safe_free(digest
);
4675 SWITCH_DECLARE(char *) switch_must_strdup(const char *_s
)
4677 char *s
= strdup(_s
);
4682 SWITCH_DECLARE(const char *) switch_memory_usage_stream(switch_stream_handle_t
*stream
)
4684 const char *status
= NULL
;
4687 * The mallinfo2() function was added in glibc 2.33.
4688 * https://man7.org/linux/man-pages/man3/mallinfo.3.html
4690 #if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 33)
4691 struct mallinfo2 mi
;
4695 stream
->write_function(stream
, "Total non-mmapped bytes (arena): %" SWITCH_SIZE_T_FMT
"\n", mi
.arena
);
4696 stream
->write_function(stream
, "# of free chunks (ordblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.ordblks
);
4697 stream
->write_function(stream
, "# of free fastbin blocks (smblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.smblks
);
4698 stream
->write_function(stream
, "# of mapped regions (hblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.hblks
);
4699 stream
->write_function(stream
, "Bytes in mapped regions (hblkhd): %" SWITCH_SIZE_T_FMT
"\n", mi
.hblkhd
);
4700 stream
->write_function(stream
, "Max. total allocated space (usmblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.usmblks
);
4701 stream
->write_function(stream
, "Free bytes held in fastbins (fsmblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.fsmblks
);
4702 stream
->write_function(stream
, "Total allocated space (uordblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.uordblks
);
4703 stream
->write_function(stream
, "Total free space (fordblks): %" SWITCH_SIZE_T_FMT
"\n", mi
.fordblks
);
4704 stream
->write_function(stream
, "Topmost releasable block (keepcost): %" SWITCH_SIZE_T_FMT
"\n", mi
.keepcost
);
4710 stream
->write_function(stream
, "Total non-mmapped bytes (arena): %u\n", mi
.arena
);
4711 stream
->write_function(stream
, "# of free chunks (ordblks): %u\n", mi
.ordblks
);
4712 stream
->write_function(stream
, "# of free fastbin blocks (smblks): %u\n", mi
.smblks
);
4713 stream
->write_function(stream
, "# of mapped regions (hblks): %u\n", mi
.hblks
);
4714 stream
->write_function(stream
, "Bytes in mapped regions (hblkhd): %u\n", mi
.hblkhd
);
4715 stream
->write_function(stream
, "Max. total allocated space (usmblks): %u\n", mi
.usmblks
);
4716 stream
->write_function(stream
, "Free bytes held in fastbins (fsmblks): %u\n", mi
.fsmblks
);
4717 stream
->write_function(stream
, "Total allocated space (uordblks): %u\n", mi
.uordblks
);
4718 stream
->write_function(stream
, "Total free space (fordblks): %u\n", mi
.fordblks
);
4719 stream
->write_function(stream
, "Topmost releasable block (keepcost): %u\n", mi
.keepcost
);
4723 switch_goto_status(NULL
, done
);
4726 /* 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 */
4728 SIZE_T BytesToAllocate
;
4731 DWORD NumberOfHeaps
;
4733 HANDLE hDefaultProcessHeap
;
4734 size_t CommittedSizeTotal
= 0;
4735 size_t UnCommittedSizeTotal
= 0;
4736 size_t SizeTotal
= 0;
4737 size_t OverheadTotal
= 0;
4739 NumberOfHeaps
= GetProcessHeaps(0, NULL
);
4740 Result
= SIZETMult(NumberOfHeaps
, sizeof(*aHeaps
), &BytesToAllocate
);
4741 if (Result
!= S_OK
) {
4742 switch_goto_status("SIZETMult failed.", done
);
4745 hDefaultProcessHeap
= GetProcessHeap();
4746 if (hDefaultProcessHeap
== NULL
) {
4747 switch_goto_status("Failed to retrieve the default process heap", done
);
4750 aHeaps
= (PHANDLE
)HeapAlloc(hDefaultProcessHeap
, 0, BytesToAllocate
);
4751 if (aHeaps
== NULL
) {
4752 switch_goto_status("HeapAlloc failed to allocate space for heaps", done
);
4755 HeapsLength
= NumberOfHeaps
;
4756 NumberOfHeaps
= GetProcessHeaps(HeapsLength
, aHeaps
);
4758 if (NumberOfHeaps
== 0) {
4759 switch_goto_status("Failed to retrieve heaps", cleanup
);
4760 } else if (NumberOfHeaps
> HeapsLength
) {
4762 * Compare the latest number of heaps with the original number of heaps.
4763 * If the latest number is larger than the original number, another
4764 * component has created a new heap and the buffer is too small.
4766 switch_goto_status("Another component created a heap between calls.", cleanup
);
4769 stream
->write_function(stream
, "Process has %d heaps.\n", HeapsLength
);
4770 for (HeapsIndex
= 0; HeapsIndex
< HeapsLength
; ++HeapsIndex
) {
4771 PROCESS_HEAP_ENTRY Entry
;
4772 HANDLE hHeap
= aHeaps
[HeapsIndex
];
4774 stream
->write_function(stream
, "Heap %d at address: %#p.\n", HeapsIndex
, aHeaps
[HeapsIndex
]);
4776 /* Lock the heap to prevent other threads from accessing the heap during enumeration. */
4777 if (HeapLock(hHeap
) == FALSE
) {
4778 switch_goto_status("Failed to lock heap.", cleanup
);
4781 Entry
.lpData
= NULL
;
4782 while (HeapWalk(hHeap
, &Entry
) != FALSE
) {
4783 if ((Entry
.wFlags
& PROCESS_HEAP_ENTRY_BUSY
) != 0) {
4784 } else if ((Entry
.wFlags
& PROCESS_HEAP_REGION
) != 0) {
4785 CommittedSizeTotal
+= Entry
.Region
.dwCommittedSize
;
4786 UnCommittedSizeTotal
+= Entry
.Region
.dwUnCommittedSize
;
4789 SizeTotal
+= Entry
.cbData
;
4790 OverheadTotal
+= Entry
.cbOverhead
;
4793 /* Unlock the heap to allow other threads to access the heap after enumeration has completed. */
4794 if (HeapUnlock(hHeap
) == FALSE
) {
4799 stream
->write_function(stream
, "Committed bytes: %" SWITCH_SIZE_T_FMT
"\n", CommittedSizeTotal
);
4800 stream
->write_function(stream
, "Uncommited bytes: %" SWITCH_SIZE_T_FMT
"\n", UnCommittedSizeTotal
);
4801 stream
->write_function(stream
, "Size: %" SWITCH_SIZE_T_FMT
"\n", SizeTotal
);
4802 stream
->write_function(stream
, "Overhead: %" SWITCH_SIZE_T_FMT
"\n", OverheadTotal
);
4805 HeapFree(hDefaultProcessHeap
, 0, aHeaps
);
4807 switch_goto_status("Memory usage statistics is not implemented on the current platform.", done
);
4814 SWITCH_DECLARE(int) switch_rand(void)
4816 uint32_t random_number
= 0;
4818 BCRYPT_ALG_HANDLE hAlgorithm
= NULL
;
4819 NTSTATUS status
= BCryptOpenAlgorithmProvider(&hAlgorithm
, BCRYPT_RNG_ALGORITHM
, NULL
, 0);
4821 if (!BCRYPT_SUCCESS(status
)) {
4822 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "BCryptOpenAlgorithmProvider failed with status %d\n", status
);
4827 status
= BCryptGenRandom(hAlgorithm
, (PUCHAR
)&random_number
, sizeof(random_number
), 0);
4828 if (!BCRYPT_SUCCESS(status
)) {
4829 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "BCryptGenRandom failed with status %d\n", status
);
4831 BCryptCloseAlgorithmProvider(hAlgorithm
, 0);
4836 BCryptCloseAlgorithmProvider(hAlgorithm
, 0);
4838 /* Make sure we return from 0 to SWITCH_RAND_MAX */
4839 return (random_number
& (SWITCH_RAND_MAX
));
4840 #elif defined(__unix__) || defined(__APPLE__)
4841 int random_fd
= open("/dev/urandom", O_RDONLY
);
4843 char error_msg
[100];
4845 if (random_fd
== -1) {
4846 strncpy(error_msg
, strerror(errno
), sizeof(error_msg
) - 1);
4847 error_msg
[sizeof(error_msg
) - 1] = '\0';
4849 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "open failed: %s\n", error_msg
);
4854 result
= read(random_fd
, &random_number
, sizeof(random_number
));
4856 strncpy(error_msg
, strerror(errno
), sizeof(error_msg
) - 1);
4857 error_msg
[sizeof(error_msg
) - 1] = '\0';
4859 switch_log_printf(SWITCH_CHANNEL_LOG
, SWITCH_LOG_ERROR
, "read failed: %s\n", error_msg
);
4868 /* Make sure we return from 0 to SWITCH_RAND_MAX */
4869 return (random_number
& (SWITCH_RAND_MAX
));
4878 * indent-tabs-mode:t
4883 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: