2006-11-30 22:02:49 +00:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
* Copyright ( C ) 2005 / 2006 , Anthony Minessale II < anthmct @ yahoo . com >
*
* Version : MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II < anthmct @ yahoo . com >
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
*
* Anthony Minessale II < anthmct @ yahoo . com >
*
* mod_enum . c - - ENUM
*
*/
# include <switch.h>
# include <udns.h>
2006-11-30 23:47:30 +00:00
# ifndef WIN32
# define closesocket close
# endif
2007-06-13 16:00:14 +00:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_enum_load ) ;
2007-09-29 01:06:08 +00:00
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_enum_shutdown ) ;
SWITCH_MODULE_DEFINITION ( mod_enum , mod_enum_load , mod_enum_shutdown , NULL ) ;
2006-11-30 22:02:49 +00:00
2008-04-10 20:26:15 +00:00
static switch_mutex_t * MUTEX = NULL ;
2006-11-30 22:02:49 +00:00
struct enum_record {
int order ;
int preference ;
char * service ;
char * route ;
2008-04-10 20:26:15 +00:00
int supported ;
2006-11-30 22:02:49 +00:00
struct enum_record * next ;
} ;
typedef struct enum_record enum_record_t ;
struct query {
2007-03-29 22:31:56 +00:00
const char * name ; /* original query string */
2006-11-30 22:02:49 +00:00
char * number ;
unsigned char dn [ DNS_MAXDN ] ;
2007-03-29 22:31:56 +00:00
enum dns_type qtyp ; /* type of the query */
2006-11-30 22:02:49 +00:00
enum_record_t * results ;
2007-12-11 20:39:55 +00:00
int errs ;
2006-11-30 22:02:49 +00:00
} ;
typedef struct query enum_query_t ;
struct route {
char * service ;
char * regex ;
char * replace ;
struct route * next ;
} ;
typedef struct route enum_route_t ;
static enum dns_class qcls = DNS_C_IN ;
static struct {
char * root ;
2007-10-17 15:20:52 +00:00
char * isn_root ;
2006-11-30 22:02:49 +00:00
enum_route_t * route_order ;
switch_memory_pool_t * pool ;
2008-04-10 20:26:15 +00:00
int auto_reload ;
2007-12-04 17:44:03 +00:00
int timeout ;
2006-11-30 22:02:49 +00:00
} globals ;
2007-10-17 15:20:52 +00:00
SWITCH_DECLARE_GLOBAL_STRING_FUNC ( set_global_root , globals . root ) ;
SWITCH_DECLARE_GLOBAL_STRING_FUNC ( set_global_isn_root , globals . isn_root ) ;
2006-11-30 22:02:49 +00:00
2007-10-17 15:20:52 +00:00
static void add_route ( char * service , char * regex , char * replace )
2006-11-30 22:02:49 +00:00
{
enum_route_t * route , * rp ;
2008-04-10 20:26:15 +00:00
route = switch_core_alloc ( globals . pool , sizeof ( * route ) ) ;
2006-11-30 22:02:49 +00:00
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
route - > service = strdup ( service ) ;
route - > regex = strdup ( regex ) ;
route - > replace = strdup ( replace ) ;
2007-03-29 22:31:56 +00:00
2008-04-10 20:26:15 +00:00
switch_mutex_lock ( MUTEX ) ;
2006-11-30 22:02:49 +00:00
if ( ! globals . route_order ) {
globals . route_order = route ;
} else {
for ( rp = globals . route_order ; rp & & rp - > next ; rp = rp - > next ) ;
rp - > next = route ;
}
2008-04-10 20:26:15 +00:00
switch_mutex_unlock ( MUTEX ) ;
2006-11-30 22:02:49 +00:00
}
static switch_status_t load_config ( void )
{
char * cf = " enum.conf " ;
2007-03-29 22:31:56 +00:00
switch_xml_t cfg , xml = NULL , param , settings , route , routes ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2006-11-30 22:02:49 +00:00
2007-03-29 22:31:56 +00:00
if ( ! ( xml = switch_xml_open_cfg ( cf , & cfg , NULL ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " open of %s failed \n " , cf ) ;
status = SWITCH_STATUS_FALSE ;
goto done ;
}
if ( ( settings = switch_xml_child ( cfg , " settings " ) ) ) {
for ( param = switch_xml_child ( settings , " param " ) ; param ; param = param - > next ) {
char * var = ( char * ) switch_xml_attr_soft ( param , " name " ) ;
char * val = ( char * ) switch_xml_attr_soft ( param , " value " ) ;
if ( ! strcasecmp ( var , " default-root " ) ) {
2006-11-30 22:02:49 +00:00
set_global_root ( val ) ;
2008-04-10 20:26:15 +00:00
} else if ( ! strcasecmp ( var , " auto-reload " ) ) {
globals . auto_reload = switch_true ( val ) ;
2007-12-04 17:44:03 +00:00
} else if ( ! strcasecmp ( var , " query-timeout " ) ) {
globals . timeout = atoi ( val ) ;
2007-10-17 15:20:52 +00:00
} else if ( ! strcasecmp ( var , " default-isn-root " ) ) {
set_global_isn_root ( val ) ;
2007-03-29 22:31:56 +00:00
} else if ( ! strcasecmp ( var , " log-level-trace " ) ) {
}
}
}
if ( ( routes = switch_xml_child ( cfg , " routes " ) ) ) {
for ( route = switch_xml_child ( routes , " route " ) ; route ; route = route - > next ) {
char * service = ( char * ) switch_xml_attr_soft ( route , " service " ) ;
char * regex = ( char * ) switch_xml_attr_soft ( route , " regex " ) ;
char * replace = ( char * ) switch_xml_attr_soft ( route , " replace " ) ;
2006-11-30 22:02:49 +00:00
if ( service & & regex & & replace ) {
add_route ( service , regex , replace ) ;
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Invalid Route! \n " ) ;
}
2007-03-29 22:31:56 +00:00
}
}
done :
2006-11-30 22:02:49 +00:00
if ( xml ) {
switch_xml_free ( xml ) ;
}
if ( ! globals . root ) {
set_global_root ( " e164.org " ) ;
}
2007-10-17 15:20:52 +00:00
if ( ! globals . isn_root ) {
set_global_isn_root ( " freenum.org " ) ;
}
2006-11-30 22:02:49 +00:00
return status ;
}
static char * reverse_number ( char * in , char * root )
{
2007-03-29 22:31:56 +00:00
switch_size_t len ;
char * out = NULL ;
char * y , * z ;
2006-11-30 22:02:49 +00:00
2007-03-29 22:31:56 +00:00
if ( ! ( in & & root ) ) {
return NULL ;
}
2006-11-30 22:02:49 +00:00
2007-03-29 22:31:56 +00:00
len = ( strlen ( in ) * 2 ) + strlen ( root ) + 1 ;
if ( ( out = malloc ( len ) ) ) {
memset ( out , 0 , len ) ;
2006-11-30 22:02:49 +00:00
2007-03-29 22:31:56 +00:00
z = out ;
for ( y = in + ( strlen ( in ) - 1 ) ; y ; y - - ) {
2006-11-30 22:02:49 +00:00
if ( * y > 47 & & * y < 58 ) {
* z + + = * y ;
* z + + = ' . ' ;
}
if ( y = = in ) {
break ;
}
2007-03-29 22:31:56 +00:00
}
strcat ( z , root ) ;
}
2006-11-30 22:02:49 +00:00
return out ;
}
2007-03-29 22:31:56 +00:00
static void dnserror ( enum_query_t * q , int errnum )
{
2007-12-11 20:39:55 +00:00
2007-03-29 22:31:56 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " unable to lookup %s record for %s: %s \n " ,
2006-11-30 22:02:49 +00:00
dns_typename ( q - > qtyp ) , dns_dntosp ( q - > dn ) , dns_strerror ( errnum ) ) ;
2007-12-11 20:39:55 +00:00
q - > errs + + ;
2006-11-30 22:02:49 +00:00
}
2008-04-10 20:26:15 +00:00
static void add_result ( enum_query_t * q , int order , int preference , char * service , char * route , int supported )
2006-11-30 22:02:49 +00:00
{
enum_record_t * new_result , * rp , * prev = NULL ;
2008-04-10 20:26:15 +00:00
new_result = malloc ( sizeof ( * new_result ) ) ;
switch_assert ( new_result ) ;
2006-11-30 22:02:49 +00:00
memset ( new_result , 0 , sizeof ( * new_result ) ) ;
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
new_result - > order = order ;
new_result - > preference = preference ;
new_result - > service = strdup ( service ) ;
new_result - > route = strdup ( route ) ;
2008-04-10 20:26:15 +00:00
new_result - > supported = supported ;
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
if ( ! q - > results ) {
q - > results = new_result ;
return ;
}
rp = q - > results ;
2007-10-12 23:49:43 +00:00
while ( rp & & strcasecmp ( rp - > service , new_result - > service ) ) {
2006-11-30 22:02:49 +00:00
prev = rp ;
rp = rp - > next ;
}
2007-10-12 23:49:43 +00:00
while ( rp & & ! strcasecmp ( rp - > service , new_result - > service ) & & new_result - > order > rp - > order ) {
2006-11-30 22:02:49 +00:00
prev = rp ;
rp = rp - > next ;
}
2007-10-12 23:49:43 +00:00
while ( rp & & ! strcasecmp ( rp - > service , new_result - > service ) & & new_result - > preference > rp - > preference ) {
2006-11-30 22:02:49 +00:00
prev = rp ;
rp = rp - > next ;
}
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
if ( prev ) {
new_result - > next = rp ;
prev - > next = new_result ;
} else {
new_result - > next = rp ;
q - > results = new_result ;
}
}
2007-03-29 22:31:56 +00:00
static void free_results ( enum_record_t * * results )
2006-11-30 22:02:49 +00:00
{
enum_record_t * fp , * rp ;
2007-03-29 22:31:56 +00:00
for ( rp = * results ; rp ; ) {
2006-11-30 22:02:49 +00:00
fp = rp ;
2006-12-01 06:12:07 +00:00
rp = rp - > next ;
2006-11-30 22:02:49 +00:00
switch_safe_free ( fp - > service ) ;
switch_safe_free ( fp - > route ) ;
switch_safe_free ( fp ) ;
}
* results = NULL ;
}
2007-03-29 22:31:56 +00:00
static void parse_rr ( const struct dns_parse * p , enum_query_t * q , struct dns_rr * rr )
{
2006-11-30 22:02:49 +00:00
const unsigned char * pkt = p - > dnsp_pkt ;
const unsigned char * end = p - > dnsp_end ;
const unsigned char * dptr = rr - > dnsrr_dptr ;
const unsigned char * dend = rr - > dnsrr_dend ;
unsigned char * dn = rr - > dnsrr_dn ;
const unsigned char * c ;
char flags ;
int order ;
int preference ;
char * service = NULL ;
char * regex = NULL ;
char * replace = NULL ;
2008-03-20 03:36:30 +00:00
char * ptr ;
2006-11-30 22:02:49 +00:00
int argc = 0 ;
2007-03-29 22:31:56 +00:00
char * argv [ 4 ] = { 0 } ;
2008-03-18 03:24:03 +00:00
int n ;
char string_arg [ 3 ] [ 256 ] = { { 0 } } ;
2006-11-30 22:02:49 +00:00
2007-03-29 22:31:56 +00:00
switch ( rr - > dnsrr_typ ) {
2008-03-18 03:24:03 +00:00
case DNS_T_NAPTR : /* prio weight port targetDN */
2006-11-30 22:02:49 +00:00
c = dptr ;
2008-03-18 03:24:03 +00:00
c + = 4 ; /* order, pref */
for ( n = 0 ; n < 3 ; + + n ) {
if ( c > = dend ) {
goto xperr ;
} else {
c + = * c + 1 ;
}
}
if ( dns_getdn ( pkt , & c , end , dn , DNS_MAXDN ) < = 0 | | c ! = dend ) {
2007-03-29 22:31:56 +00:00
goto xperr ;
2008-03-18 03:24:03 +00:00
}
2006-11-30 22:02:49 +00:00
c = dptr ;
2008-03-18 03:24:03 +00:00
order = dns_get16 ( c + 0 ) ;
preference = dns_get16 ( c + 2 ) ;
flags = ( char ) dns_get16 ( c + 4 ) ;
c + = 4 ;
2007-03-29 22:31:56 +00:00
2008-03-18 03:24:03 +00:00
for ( n = 0 ; n < 3 ; n + + ) {
uint32_t len = * c + + , cpylen = len ;
2008-03-19 02:20:23 +00:00
switch_assert ( string_arg [ n ] ) ;
2008-03-18 03:24:03 +00:00
if ( len > sizeof ( string_arg [ n ] ) - 1 ) {
cpylen = sizeof ( string_arg [ n ] ) - 1 ;
}
strncpy ( string_arg [ n ] , ( char * ) c , cpylen ) ;
* ( string_arg [ n ] + len ) = ' \0 ' ;
c + = len ;
}
2006-11-30 22:02:49 +00:00
2008-03-18 03:24:03 +00:00
service = string_arg [ 1 ] ;
2006-11-30 22:02:49 +00:00
2008-03-18 03:24:03 +00:00
if ( ( argc = switch_separate_string ( string_arg [ 2 ] , ' ! ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
2006-11-30 22:02:49 +00:00
regex = argv [ 1 ] ;
replace = argv [ 2 ] ;
2008-03-18 03:24:03 +00:00
} else {
goto xperr ;
2006-11-30 22:02:49 +00:00
}
2008-03-20 03:36:30 +00:00
for ( ptr = replace ; ptr & & * ptr ; ptr + + ) {
if ( * ptr = = ' \\ ' ) {
* ptr = ' $ ' ;
}
}
2006-11-30 22:02:49 +00:00
if ( flags & & service & & regex & & replace ) {
2007-03-09 20:44:13 +00:00
switch_regex_t * re = NULL ;
2006-11-30 22:02:49 +00:00
int proceed = 0 , ovector [ 30 ] ;
char substituted [ 1024 ] = " " ;
char rbuf [ 1024 ] = " " ;
char * uri ;
enum_route_t * route ;
2008-04-10 20:26:15 +00:00
int supported = 0 ;
2007-03-09 20:44:13 +00:00
switch_regex_safe_free ( re ) ;
2006-11-30 22:02:49 +00:00
2007-03-09 20:44:13 +00:00
if ( ( proceed = switch_regex_perform ( q - > number , regex , & re , ovector , sizeof ( ovector ) / sizeof ( ovector [ 0 ] ) ) ) ) {
2006-11-30 22:02:49 +00:00
if ( strchr ( regex , ' ( ' ) ) {
2007-03-30 00:13:31 +00:00
switch_perform_substitution ( re , proceed , replace , q - > number , substituted , sizeof ( substituted ) , ovector ) ;
2006-11-30 22:02:49 +00:00
uri = substituted ;
} else {
uri = replace ;
}
2008-04-10 20:26:15 +00:00
switch_mutex_lock ( MUTEX ) ;
for ( route = globals . route_order ; route ; route = route - > next ) {
if ( strcasecmp ( service , route - > service ) ) {
continue ;
}
2007-03-09 20:44:13 +00:00
switch_regex_safe_free ( re ) ;
2007-03-30 00:13:31 +00:00
if ( ( proceed = switch_regex_perform ( uri , route - > regex , & re , ovector , sizeof ( ovector ) / sizeof ( ovector [ 0 ] ) ) ) ) {
2006-11-30 22:02:49 +00:00
if ( strchr ( route - > regex , ' ( ' ) ) {
switch_perform_substitution ( re , proceed , route - > replace , uri , rbuf , sizeof ( rbuf ) , ovector ) ;
uri = rbuf ;
} else {
uri = route - > replace ;
}
2008-04-10 20:26:15 +00:00
supported + + ;
add_result ( q , order , preference , service , uri , supported ) ;
2006-11-30 22:02:49 +00:00
}
}
2008-04-10 20:26:15 +00:00
if ( ! supported ) {
add_result ( q , order , preference , service , uri , 0 ) ;
}
}
switch_mutex_unlock ( MUTEX ) ;
2006-11-30 22:02:49 +00:00
2007-03-09 20:44:13 +00:00
switch_regex_safe_free ( re ) ;
2006-11-30 22:02:49 +00:00
}
break ;
default :
break ;
}
return ;
2008-03-18 03:24:03 +00:00
xperr :
2006-11-30 22:02:49 +00:00
//printf("<parse error>\n");
return ;
}
2007-03-29 22:31:56 +00:00
static void dnscb ( struct dns_ctx * ctx , void * result , void * data )
{
2006-11-30 22:02:49 +00:00
int r = dns_status ( ctx ) ;
enum_query_t * q = data ;
struct dns_parse p ;
struct dns_rr rr ;
unsigned nrr ;
unsigned char dn [ DNS_MAXDN ] ;
const unsigned char * pkt , * cur , * end , * qdn ;
if ( ! result ) {
dnserror ( q , r ) ;
return ;
}
2007-03-29 22:31:56 +00:00
pkt = result ;
end = pkt + r ;
cur = dns_payload ( pkt ) ;
2006-11-30 22:02:49 +00:00
dns_getdn ( pkt , & cur , end , dn , sizeof ( dn ) ) ;
dns_initparse ( & p , NULL , pkt , cur , end ) ;
2007-05-04 02:09:24 +00:00
p . dnsp_qcls = 0 ;
p . dnsp_qtyp = 0 ;
2006-11-30 22:02:49 +00:00
qdn = dn ;
nrr = 0 ;
2007-03-29 22:31:56 +00:00
while ( ( r = dns_nextrr ( & p , & rr ) ) > 0 ) {
if ( ! dns_dnequal ( qdn , rr . dnsrr_dn ) )
continue ;
if ( ( qcls = = DNS_C_ANY | | qcls = = rr . dnsrr_cls ) & & ( q - > qtyp = = DNS_T_ANY | | q - > qtyp = = rr . dnsrr_typ ) )
2006-11-30 22:02:49 +00:00
+ + nrr ;
else if ( rr . dnsrr_typ = = DNS_T_CNAME & & ! nrr ) {
2007-03-30 00:13:31 +00:00
if ( dns_getdn ( pkt , & rr . dnsrr_dptr , end , p . dnsp_dnbuf , sizeof ( p . dnsp_dnbuf ) ) < = 0 | | rr . dnsrr_dptr ! = rr . dnsrr_dend ) {
2006-11-30 22:02:49 +00:00
r = DNS_E_PROTOCOL ;
break ;
2007-03-29 22:31:56 +00:00
} else {
2006-11-30 22:02:49 +00:00
qdn = p . dnsp_dnbuf ;
}
}
}
if ( ! r & & ! nrr )
r = DNS_E_NODATA ;
if ( r < 0 ) {
dnserror ( q , r ) ;
free ( result ) ;
return ;
}
dns_rewind ( & p , NULL ) ;
p . dnsp_qtyp = q - > qtyp ;
p . dnsp_qcls = qcls ;
2007-03-29 22:31:56 +00:00
while ( dns_nextrr ( & p , & rr ) ) {
2006-11-30 22:02:49 +00:00
parse_rr ( & p , q , & rr ) ;
}
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
free ( result ) ;
}
2007-03-29 22:31:56 +00:00
static switch_status_t enum_lookup ( char * root , char * in , enum_record_t * * results )
2006-11-30 22:02:49 +00:00
{
2007-03-29 22:31:56 +00:00
switch_status_t sstatus = SWITCH_STATUS_SUCCESS ;
2006-11-30 22:02:49 +00:00
char * name = NULL ;
2007-03-29 22:31:56 +00:00
enum_query_t query = { 0 } ;
2006-11-30 22:02:49 +00:00
enum dns_type l_qtyp = DNS_T_NAPTR ;
2007-12-10 16:50:50 +00:00
int i = 0 , abs = 0 , j = 0 ;
2007-03-29 22:31:56 +00:00
dns_socket fd = ( dns_socket ) - 1 ;
2006-11-30 22:02:49 +00:00
fd_set fds ;
2007-03-29 22:31:56 +00:00
struct timeval tv = { 0 } ;
2006-11-30 22:02:49 +00:00
time_t now = 0 ;
struct dns_ctx * nctx = NULL ;
2007-10-17 15:20:52 +00:00
char * num , * mnum = NULL , * mroot = NULL , * p ;
2007-03-29 22:31:56 +00:00
2007-10-17 15:20:52 +00:00
mnum = switch_mprintf ( " %s%s " , * in = = ' + ' ? " " : " + " , in ) ;
if ( ( p = strchr ( mnum , ' * ' ) ) ) {
* p + + = ' \0 ' ;
mroot = switch_mprintf ( " %s.%s " , p , root ? root : globals . isn_root ) ;
root = mroot ;
2006-11-30 22:02:49 +00:00
}
2007-10-17 15:20:52 +00:00
if ( switch_strlen_zero ( root ) ) {
root = globals . root ;
}
num = mnum ;
2006-11-30 22:02:49 +00:00
if ( ! ( name = reverse_number ( num , root ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Parse Error! \n " ) ;
sstatus = SWITCH_STATUS_FALSE ;
goto done ;
}
if ( ! ( nctx = dns_new ( NULL ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Memory Error! \n " ) ;
sstatus = SWITCH_STATUS_MEMERR ;
goto done ;
}
fd = dns_open ( nctx ) ;
if ( fd < 0 ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " FD Error! \n " ) ;
sstatus = SWITCH_STATUS_FALSE ;
goto done ;
}
2007-03-29 22:31:56 +00:00
dns_ptodn ( name , ( unsigned int ) strlen ( name ) , query . dn , sizeof ( query . dn ) , & abs ) ;
2006-11-30 22:02:49 +00:00
query . name = name ;
query . number = num ;
query . qtyp = l_qtyp ;
if ( abs ) {
abs = DNS_NOSRCH ;
}
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
if ( ! dns_submit_dn ( nctx , query . dn , qcls , l_qtyp , abs , 0 , dnscb , & query ) ) {
dnserror ( & query , dns_status ( nctx ) ) ;
}
FD_ZERO ( & fds ) ;
now = 0 ;
2007-12-10 16:50:50 +00:00
while ( ( i = dns_timeouts ( nctx , 1 , now ) ) > 0 ) {
2006-11-30 23:33:37 +00:00
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4389 4127)
# endif
2006-11-30 22:02:49 +00:00
FD_SET ( fd , & fds ) ;
2006-11-30 23:33:37 +00:00
# ifdef _MSC_VER
# pragma warning(pop)
# endif
2007-12-10 16:50:50 +00:00
j + = i ;
2007-12-11 20:39:55 +00:00
if ( j > globals . timeout | | query . results | | query . errs ) {
2007-12-10 16:50:50 +00:00
break ;
}
2006-11-30 22:02:49 +00:00
tv . tv_sec = i ;
tv . tv_usec = 0 ;
2007-03-29 22:31:56 +00:00
i = select ( ( int ) ( fd + 1 ) , & fds , 0 , 0 , & tv ) ;
2008-01-11 00:43:49 +00:00
now = switch_timestamp ( NULL ) ;
2007-12-11 20:39:55 +00:00
if ( i > 0 ) {
2007-03-29 22:31:56 +00:00
dns_ioevent ( nctx , now ) ;
2007-12-11 20:39:55 +00:00
}
2006-11-30 22:02:49 +00:00
}
if ( ! query . results ) {
sstatus = SWITCH_STATUS_FALSE ;
}
* results = query . results ;
query . results = NULL ;
2007-03-29 22:31:56 +00:00
done :
2006-11-30 22:02:49 +00:00
if ( fd > - 1 ) {
2006-11-30 23:47:30 +00:00
closesocket ( fd ) ;
2007-03-29 22:31:56 +00:00
fd = ( dns_socket ) - 1 ;
2006-11-30 22:02:49 +00:00
}
if ( nctx ) {
dns_free ( nctx ) ;
}
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
switch_safe_free ( name ) ;
switch_safe_free ( mnum ) ;
2007-10-17 15:20:52 +00:00
switch_safe_free ( mroot ) ;
2006-11-30 22:02:49 +00:00
return sstatus ;
}
2007-06-20 06:14:57 +00:00
SWITCH_STANDARD_DIALPLAN ( enum_dialplan_hunt )
2006-11-30 22:02:49 +00:00
{
switch_caller_extension_t * extension = NULL ;
enum_record_t * results , * rp ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2007-01-28 21:43:00 +00:00
char * dp = ( char * ) arg ;
2006-11-30 22:02:49 +00:00
2007-04-20 23:45:14 +00:00
if ( ! caller_profile ) {
caller_profile = switch_channel_get_caller_profile ( channel ) ;
}
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " ENUM Lookup on %s \n " , caller_profile - > destination_number ) ;
2007-10-17 15:20:52 +00:00
if ( enum_lookup ( dp , caller_profile - > destination_number , & results ) = = SWITCH_STATUS_SUCCESS ) {
2007-03-30 00:13:31 +00:00
if ( ( extension = switch_caller_extension_new ( session , caller_profile - > destination_number , caller_profile - > destination_number ) ) = = 0 ) {
2006-11-30 22:02:49 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " memory error! \n " ) ;
2007-03-29 22:31:56 +00:00
free_results ( & results ) ;
2006-11-30 22:02:49 +00:00
return NULL ;
}
switch_channel_set_variable ( channel , SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE , " true " ) ;
2007-03-29 22:31:56 +00:00
2008-04-10 20:26:15 +00:00
for ( rp = results ; rp ; rp = rp - > next ) {
if ( ! rp - > supported ) {
continue ;
2006-11-30 22:02:49 +00:00
}
2008-04-10 20:26:15 +00:00
switch_caller_extension_add_application ( session , extension , " bridge " , rp - > route ) ;
2006-11-30 22:02:49 +00:00
}
2008-04-10 20:26:15 +00:00
2006-11-30 22:02:49 +00:00
2007-03-29 22:31:56 +00:00
free_results ( & results ) ;
2006-11-30 22:02:49 +00:00
}
return extension ;
}
2007-06-20 06:05:31 +00:00
SWITCH_STANDARD_APP ( enum_app_function )
2006-11-30 22:02:49 +00:00
{
int argc = 0 ;
2007-03-29 22:31:56 +00:00
char * argv [ 4 ] = { 0 } ;
2006-11-30 22:02:49 +00:00
char * mydata = NULL ;
char * dest = NULL , * root = NULL ;
enum_record_t * results , * rp ;
char rbuf [ 1024 ] = " " ;
char vbuf [ 1024 ] = " " ;
char * rbp = rbuf ;
switch_size_t l = 0 , rbl = sizeof ( rbuf ) ;
2006-12-01 15:26:37 +00:00
uint32_t cnt = 1 ;
2006-11-30 22:02:49 +00:00
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2008-04-10 00:53:33 +00:00
int last_order = - 1 , last_pref = - 2 ;
char * last_delim = " | " ;
2006-11-30 22:02:49 +00:00
if ( ! ( mydata = switch_core_session_strdup ( session , data ) ) ) {
2007-03-29 22:31:56 +00:00
return ;
}
2006-11-30 22:02:49 +00:00
2007-03-29 22:31:56 +00:00
if ( ( argc = switch_separate_string ( mydata , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
2006-11-30 22:02:49 +00:00
dest = argv [ 0 ] ;
2007-10-17 15:20:52 +00:00
root = argv [ 1 ] ;
2007-10-12 19:22:50 +00:00
if ( enum_lookup ( root , dest , & results ) = = SWITCH_STATUS_SUCCESS ) {
2007-09-29 01:06:08 +00:00
switch_event_header_t * hi ;
2007-09-24 19:34:25 +00:00
if ( ( hi = switch_channel_variable_first ( channel ) ) ) {
2007-09-29 01:06:08 +00:00
for ( ; hi ; hi = hi - > next ) {
char * vvar = hi - > name ;
2007-04-28 21:48:03 +00:00
if ( vvar & & ! strncmp ( vvar , " enum_ " , 5 ) ) {
switch_channel_set_variable ( channel , ( char * ) vvar , NULL ) ;
}
2006-12-01 15:26:37 +00:00
}
2007-04-28 21:48:03 +00:00
switch_channel_variable_last ( channel ) ;
2006-12-01 15:26:37 +00:00
}
2008-04-10 20:26:15 +00:00
for ( rp = results ; rp ; rp = rp - > next ) {
if ( ! rp - > supported ) {
continue ;
2006-11-30 22:02:49 +00:00
}
2008-04-10 20:26:15 +00:00
switch_snprintf ( vbuf , sizeof ( vbuf ) , " enum_route_%d " , cnt + + ) ;
switch_channel_set_variable ( channel , vbuf , rp - > route ) ;
if ( rp - > preference = = last_pref & & rp - > order = = last_order ) {
* last_delim = ' , ' ;
}
switch_snprintf ( rbp , rbl , " %s| " , rp - > route ) ;
last_delim = end_of_p ( rbp ) ;
last_order = rp - > order ;
last_pref = rp - > preference ;
l = strlen ( rp - > route ) + 1 ;
rbp + = l ;
rbl - = l ;
2006-11-30 22:02:49 +00:00
}
2008-04-10 20:26:15 +00:00
2007-12-12 21:53:32 +00:00
switch_snprintf ( vbuf , sizeof ( vbuf ) , " %d " , cnt ) ;
2006-12-01 15:26:37 +00:00
switch_channel_set_variable ( channel , " enum_route_count " , vbuf ) ;
2007-03-29 22:31:56 +00:00
* ( rbuf + strlen ( rbuf ) - 1 ) = ' \0 ' ;
2006-11-30 22:02:49 +00:00
switch_channel_set_variable ( channel , " enum_auto_route " , rbuf ) ;
2007-03-29 22:31:56 +00:00
free_results ( & results ) ;
2006-11-30 22:02:49 +00:00
}
}
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
}
2008-04-10 00:53:33 +00:00
SWITCH_STANDARD_API ( enum_api )
{
int argc = 0 ;
char * argv [ 4 ] = { 0 } ;
char * mydata = NULL ;
char * dest = NULL , * root = NULL ;
enum_record_t * results , * rp ;
char rbuf [ 1024 ] = " " ;
char * rbp = rbuf ;
switch_size_t l = 0 , rbl = sizeof ( rbuf ) ;
int last_order = - 1 , last_pref = - 2 ;
char * last_delim = " | " ;
2008-04-10 15:42:13 +00:00
int ok = 0 ;
if ( switch_strlen_zero ( cmd ) ) {
stream - > write_function ( stream , " %s " , " none " ) ;
return SWITCH_STATUS_SUCCESS ;
}
2008-04-10 00:53:33 +00:00
if ( ! ( mydata = strdup ( cmd ) ) ) {
abort ( ) ;
}
if ( ( argc = switch_separate_string ( mydata , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
dest = argv [ 0 ] ;
root = argv [ 1 ] ;
if ( enum_lookup ( root , dest , & results ) = = SWITCH_STATUS_SUCCESS ) {
2008-04-10 20:26:15 +00:00
for ( rp = results ; rp ; rp = rp - > next ) {
if ( ! rp - > supported ) {
continue ;
2008-04-10 00:53:33 +00:00
}
2008-04-10 20:26:15 +00:00
if ( rp - > preference = = last_pref & & rp - > order = = last_order ) {
* last_delim = ' , ' ;
}
switch_snprintf ( rbp , rbl , " %s| " , rp - > route ) ;
last_delim = end_of_p ( rbp ) ;
last_order = rp - > order ;
last_pref = rp - > preference ;
l = strlen ( rp - > route ) + 1 ;
rbp + = l ;
rbl - = l ;
2008-04-10 00:53:33 +00:00
}
* ( rbuf + strlen ( rbuf ) - 1 ) = ' \0 ' ;
stream - > write_function ( stream , " %s " , rbuf ) ;
free_results ( & results ) ;
2008-04-10 15:42:13 +00:00
ok + + ;
2008-04-10 00:53:33 +00:00
}
}
switch_safe_free ( mydata ) ;
2008-04-10 15:42:13 +00:00
if ( ! ok ) {
stream - > write_function ( stream , " %s " , " none " ) ;
}
2008-04-10 00:53:33 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-04-10 20:26:15 +00:00
static void do_load ( void )
{
switch_mutex_lock ( MUTEX ) ;
if ( globals . pool ) {
switch_core_destroy_memory_pool ( & globals . pool ) ;
}
memset ( & globals , 0 , sizeof ( globals ) ) ;
switch_core_new_memory_pool ( & globals . pool ) ;
globals . timeout = 10 ;
load_config ( ) ;
switch_mutex_unlock ( MUTEX ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " ENUM Reloaded \n " ) ;
}
2007-05-12 21:36:15 +00:00
SWITCH_STANDARD_API ( enum_function )
2006-11-30 22:02:49 +00:00
{
int argc = 0 ;
2007-03-29 22:31:56 +00:00
char * argv [ 4 ] = { 0 } ;
2006-11-30 22:02:49 +00:00
enum_record_t * results , * rp ;
char * mydata = NULL ;
char * dest = NULL , * root = NULL ;
if ( session ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " This function cannot be called from the dialplan. \n " ) ;
return SWITCH_STATUS_FALSE ;
}
2007-05-12 21:36:15 +00:00
if ( ! cmd | | ! ( mydata = strdup ( cmd ) ) ) {
2008-04-10 20:26:15 +00:00
stream - > write_function ( stream , " Usage: enum [reload | <number> [<root>] ] \n " ) ;
2007-10-17 15:20:52 +00:00
return SWITCH_STATUS_SUCCESS ;
2006-11-30 22:02:49 +00:00
}
if ( ( argc = switch_separate_string ( mydata , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
dest = argv [ 0 ] ;
2007-10-17 15:20:52 +00:00
root = argv [ 1 ] ;
2008-04-10 20:26:15 +00:00
if ( ! strcasecmp ( dest , " reload " ) ) {
do_load ( ) ;
stream - > write_function ( stream , " +OK ENUM Reloaded. \n " ) ;
return SWITCH_STATUS_SUCCESS ;
}
2007-03-29 22:31:56 +00:00
2007-05-12 14:48:14 +00:00
if ( ! enum_lookup ( root , dest , & results ) = = SWITCH_STATUS_SUCCESS ) {
2006-11-30 22:02:49 +00:00
stream - > write_function ( stream , " No Match! \n " ) ;
return SWITCH_STATUS_SUCCESS ;
}
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
stream - > write_function ( stream ,
" \n Offered Routes: \n "
2007-03-30 00:13:31 +00:00
" Order \t Pref \t Service \t Route \n " " ============================================================================== \n " ) ;
2006-11-30 22:02:49 +00:00
2007-03-29 22:31:56 +00:00
for ( rp = results ; rp ; rp = rp - > next ) {
2006-11-30 22:02:49 +00:00
stream - > write_function ( stream , " %d \t %d \t %-10s \t %s \n " , rp - > order , rp - > preference , rp - > service , rp - > route ) ;
}
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
stream - > write_function ( stream ,
" \n Supported Routes: \n "
2007-03-30 00:13:31 +00:00
" Order \t Pref \t Service \t Route \n " " ============================================================================== \n " ) ;
2006-11-30 22:02:49 +00:00
2008-04-10 20:26:15 +00:00
for ( rp = results ; rp ; rp = rp - > next ) {
if ( rp - > supported ) {
stream - > write_function ( stream , " %d \t %d \t %-10s \t %s \n " , rp - > order , rp - > preference , rp - > service , rp - > route ) ;
2006-11-30 22:02:49 +00:00
}
}
2007-03-29 22:31:56 +00:00
2006-11-30 22:02:49 +00:00
free_results ( & results ) ;
} else {
stream - > write_function ( stream , " Invalid Input! \n " ) ;
}
return SWITCH_STATUS_SUCCESS ;
}
2008-04-10 20:26:15 +00:00
static void event_handler ( switch_event_t * event )
{
if ( globals . auto_reload ) {
do_load ( ) ;
}
}
2007-06-13 16:00:14 +00:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_enum_load )
2006-11-30 22:02:49 +00:00
{
2007-06-20 06:05:31 +00:00
switch_api_interface_t * api_interface ;
switch_application_interface_t * app_interface ;
switch_dialplan_interface_t * dp_interface ;
2006-11-30 22:02:49 +00:00
2008-04-10 20:26:15 +00:00
switch_mutex_init ( & MUTEX , SWITCH_MUTEX_NESTED , pool ) ;
2006-11-30 22:02:49 +00:00
if ( dns_init ( 0 ) < 0 ) {
return SWITCH_STATUS_FALSE ;
}
2007-06-20 06:05:31 +00:00
memset ( & globals , 0 , sizeof ( globals ) ) ;
2008-04-10 20:26:15 +00:00
do_load ( ) ;
if ( switch_event_bind ( modname , SWITCH_EVENT_RELOADXML , NULL , event_handler , NULL ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't bind! \n " ) ;
return SWITCH_STATUS_TERM ;
}
2006-11-30 22:02:49 +00:00
/* connect my internal structure to the blank pointer passed to me */
2007-06-20 06:05:31 +00:00
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
SWITCH_ADD_API ( api_interface , " enum " , " ENUM " , enum_function , " " ) ;
2008-04-10 00:53:33 +00:00
SWITCH_ADD_API ( api_interface , " enum_auto " , " ENUM " , enum_api , " " ) ;
2008-04-11 23:26:47 +00:00
SWITCH_ADD_APP ( app_interface , " enum " , " Perform an ENUM lookup " , " Perform an ENUM lookup " , enum_app_function , " [reload | <number> [<root>]] " , SAF_SUPPORT_NOMEDIA ) ;
2007-06-20 06:05:31 +00:00
SWITCH_ADD_DIALPLAN ( dp_interface , " enum " , enum_dialplan_hunt ) ;
2006-11-30 22:02:49 +00:00
2008-04-10 20:26:15 +00:00
2006-11-30 22:02:49 +00:00
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS ;
}
2007-09-29 01:06:08 +00:00
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_enum_shutdown )
{
2008-04-10 20:26:15 +00:00
if ( globals . pool ) {
switch_core_destroy_memory_pool ( & globals . pool ) ;
}
2007-09-29 01:06:08 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2008-01-27 05:02:52 +00:00
/* For Emacs:
* Local Variables :
* mode : c
2008-02-03 22:14:57 +00:00
* indent - tabs - mode : t
2008-01-27 05:02:52 +00:00
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 expandtab :
*/