2010-07-13 12:15:46 +00:00
/*
Serval Distributed Numbering Architecture ( DNA )
Copyright ( C ) 2010 Paul Gardner - Stephen
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
2012-02-05 05:45:19 +00:00
# include <sys/socket.h>
# include <netinet/in.h>
2012-02-23 02:15:42 +00:00
# include "serval.h"
2010-07-13 12:15:46 +00:00
unsigned char * hlr = NULL ;
int hlr_size = 0 ;
2011-05-05 09:10:38 +00:00
FILE * i_f = NULL ;
2010-07-13 12:15:46 +00:00
struct in_addr client_addr ;
int client_port ;
2011-08-08 14:41:46 +00:00
int getBackingStore ( char * s , int size ) ;
int createServerSocket ( ) ;
int simpleServerMode ( ) ;
2012-02-05 05:45:19 +00:00
int recvwithttl ( int sock , unsigned char * buffer , int bufferlen , int * ttl ,
struct sockaddr * recvaddr , unsigned int * recvaddrlen )
{
struct msghdr msg ;
struct iovec iov [ 1 ] ;
iov [ 0 ] . iov_base = buffer ;
iov [ 0 ] . iov_len = bufferlen ;
bzero ( & msg , sizeof ( msg ) ) ;
msg . msg_name = recvaddr ;
msg . msg_namelen = * recvaddrlen ;
msg . msg_iov = & iov [ 0 ] ;
msg . msg_iovlen = 1 ;
// setting the following makes the data end up in the wrong place
// msg.msg_iov->iov_base=iov_buffer;
// msg.msg_iov->iov_len=sizeof(iov_buffer);
struct cmsghdr cmsgcmsg [ 16 ] ;
msg . msg_control = & cmsgcmsg [ 0 ] ;
msg . msg_controllen = sizeof ( struct cmsghdr ) * 16 ;
msg . msg_flags = 0 ;
fcntl ( sock , F_SETFL , O_NONBLOCK ) ;
int len = recvmsg ( sock , & msg , 0 ) ;
2012-02-15 13:08:23 +00:00
if ( debug & DEBUG_PACKETXFER )
fprintf ( stderr , " recvmsg returned %d bytes (flags=%d,msg_controllen=%d) \n " ,
len , msg . msg_flags , msg . msg_controllen ) ;
2012-02-05 05:45:19 +00:00
2012-02-15 13:08:23 +00:00
struct cmsghdr * cmsg ;
if ( len > 0 )
{
for ( cmsg = CMSG_FIRSTHDR ( & msg ) ;
cmsg ! = NULL ;
cmsg = CMSG_NXTHDR ( & msg , cmsg ) ) {
if ( ( cmsg - > cmsg_level = = IPPROTO_IP ) & &
( ( cmsg - > cmsg_type = = IP_RECVTTL ) | | ( cmsg - > cmsg_type = = IP_TTL ) )
& & ( cmsg - > cmsg_len ) ) {
if ( debug & DEBUG_PACKETXFER )
fprintf ( stderr , " TTL (%p) data location resolves to %p \n " ,
ttl , CMSG_DATA ( cmsg ) ) ;
if ( CMSG_DATA ( cmsg ) ) {
* ttl = * ( unsigned char * ) CMSG_DATA ( cmsg ) ;
if ( debug & DEBUG_PACKETXFER )
fprintf ( stderr , " TTL of packet is %d \n " , * ttl ) ;
}
} else {
if ( debug & DEBUG_PACKETXFER )
fprintf ( stderr , " I didn't expect to see level=%02x, type=%02x \n " ,
cmsg - > cmsg_level , cmsg - > cmsg_type ) ;
}
}
2012-02-05 05:45:19 +00:00
}
* recvaddrlen = msg . msg_namelen ;
return len ;
}
2011-08-08 14:41:46 +00:00
2010-07-13 12:15:46 +00:00
int server ( char * backing_file , int size , int foregroundMode )
{
2011-08-08 14:41:46 +00:00
/* Get backing store for HLR */
getBackingStore ( backing_file , size ) ;
if ( overlayMode )
{
/* Now find and initialise all the suitable network interfaces, i.e.,
those running IPv4 .
Packet radio dongles will get discovered later as the interfaces get probed .
This will setup the sockets for the server to communicate on each interface .
XXX - Problems may persist where the same address is used on multiple interfaces ,
but otherwise hopefully it will allow us to bridge multiple networks .
*/
overlay_interface_discover ( ) ;
}
else
{
/* Create a simple socket for listening on if we are not in overlay mesh mode. */
createServerSocket ( ) ;
}
/* Detach from the console */
if ( ! foregroundMode ) daemon ( 0 , 0 ) ;
2012-03-04 22:57:31 +00:00
/* Record PID */
char filename [ 1024 ] ;
char * instancepath = getenv ( " SERVALINSTANCE_PATH " ) ;
if ( ! instancepath ) instancepath = DEFAULT_INSTANCE_PATH ;
snprintf ( filename , 1023 , " %s/serval.pid " , instancepath ) ; filename [ 1023 ] = 0 ;
FILE * f = fopen ( filename , " w " ) ;
if ( ! f ) {
WHY ( " Could not write to PID file " ) ;
exit ( - 1 ) ;
}
fprintf ( f , " %d \n " , getpid ( ) ) ;
fclose ( f ) ;
2011-08-08 14:41:46 +00:00
if ( ! overlayMode ) simpleServerMode ( ) ;
2011-08-14 08:36:39 +00:00
else overlayServerMode ( ) ;
2011-08-08 14:41:46 +00:00
return 0 ;
}
int getBackingStore ( char * backing_file , int size )
{
if ( ! backing_file )
2010-07-13 12:15:46 +00:00
{
/* transitory storage of HLR data, so just malloc() the memory */
hlr = calloc ( size , 1 ) ;
if ( ! hlr ) exit ( setReason ( " Failed to calloc() HLR database. " ) ) ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " Allocated %d byte temporary HLR store \n " , size ) ;
2010-07-13 12:15:46 +00:00
}
else
{
unsigned char zero [ 8192 ] ;
FILE * f = fopen ( backing_file , " r+ " ) ;
if ( ! f ) f = fopen ( backing_file , " w+ " ) ;
if ( ! f ) exit ( setReason ( " Could not open backing file. " ) ) ;
bzero ( & zero [ 0 ] , 8192 ) ;
fseek ( f , 0 , SEEK_END ) ;
errno = 0 ;
while ( ftell ( f ) < size )
{
int r ;
fseek ( f , 0 , SEEK_END ) ;
if ( ( r = fwrite ( zero , 8192 , 1 , f ) ) ! = 1 )
{
perror ( " fwrite " ) ;
exit ( setReason ( " Could not enlarge backing file to requested size (short write) " ) ) ;
}
fseek ( f , 0 , SEEK_END ) ;
}
if ( errno ) perror ( " fseek " ) ;
if ( fwrite ( " " , 1 , 1 , f ) ! = 1 )
{
fprintf ( stderr , " Failed to set backing file size. \n " ) ;
perror ( " fwrite " ) ;
}
hlr = ( unsigned char * ) mmap ( NULL , size , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_NORESERVE , fileno ( f ) , 0 ) ;
if ( hlr = = MAP_FAILED ) {
perror ( " mmap " ) ;
exit ( setReason ( " Memory mapping of HLR backing file failed. " ) ) ;
}
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " Allocated %d byte HLR store backed by file `%s' \n " ,
2010-07-13 12:15:46 +00:00
size , backing_file ) ;
}
hlr_size = size ;
2011-08-09 06:10:27 +00:00
seedHlr ( ) ;
2011-08-08 14:41:46 +00:00
return 0 ;
2010-07-13 12:15:46 +00:00
}
int processRequest ( unsigned char * packet , int len ,
struct sockaddr * sender , int sender_len ,
2012-02-05 05:45:19 +00:00
unsigned char * transaction_id , int recvttl , char * did , char * sid )
2010-07-13 12:15:46 +00:00
{
/* Find HLR entry by DID or SID, unless creating */
2011-03-22 06:33:14 +00:00
int ofs , rofs = 0 ;
2010-07-13 12:15:46 +00:00
int records_searched = 0 ;
int prev_pofs = 0 ;
int pofs = OFS_PAYLOAD ;
while ( pofs < len )
{
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_DNAREQUESTS ) fprintf ( stderr , " processRequest: len=%d, pofs=%d, pofs_prev=%d \n " , len , pofs , prev_pofs ) ;
2010-07-13 12:15:46 +00:00
/* Avoid infinite loops */
if ( pofs < = prev_pofs ) break ;
prev_pofs = pofs ;
if ( packet [ pofs ] = = ACTION_CREATEHLR )
{
2012-03-06 08:36:07 +00:00
/* Creating an HLR requires an initial DID number and definitely no SID -
2010-07-13 12:15:46 +00:00
you can ' t choose a SID . */
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " Creating a new HLR record. did='%s', sid='%s' \n " , did , sid ) ;
2012-02-05 05:45:19 +00:00
if ( ! did [ 0 ] ) return respondSimple ( NULL , ACTION_DECLINED , NULL , 0 , transaction_id , recvttl , sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
if ( sid [ 0 ] ) return respondSimple ( sid , ACTION_DECLINED , NULL , 0 , transaction_id , recvttl , sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " Verified that create request supplies DID but not SID \n " ) ;
2010-07-13 12:15:46 +00:00
{
2012-03-06 08:36:07 +00:00
/* Look for an existing HLR with the requested DID. If there is one, respond with its
SID . This handles duplicates of the same message . If there is none , then make a new
HLR with random SID and initial DID . */
int ofs = 0 ;
2012-03-13 08:01:29 +00:00
int response = ACTION_DECLINED ;
if ( findHlr ( hlr , & ofs , sid , did ) ) {
hlrSid ( hlr , ofs , sid ) ;
if ( debug & DEBUG_HLR ) fprintf ( stderr , " HLR found with did='%s' at ofs=%x: sid='%s' \n " , did , ofs , sid ) ;
response = ACTION_OKAY ;
2012-03-06 08:36:07 +00:00
}
2012-03-13 08:01:29 +00:00
else if ( createHlr ( did , sid ) = = 0 ) {
if ( debug & DEBUG_HLR ) fprintf ( stderr , " HLR created with did='%s': sid='%s' \n " , did , sid ) ;
response = ACTION_OKAY ;
}
return respondSimple ( sid , response , NULL , 0 , transaction_id , recvttl , sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2010-07-13 12:15:46 +00:00
}
pofs + = 1 ;
pofs + = 1 + SID_SIZE ;
}
else
{
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_DNAREQUESTS ) fprintf ( stderr , " Looking at action code 0x%02x @ packet offset 0x%x \n " ,
2011-10-05 22:46:47 +00:00
packet [ pofs ] , pofs ) ;
2010-07-13 12:15:46 +00:00
switch ( packet [ pofs ] )
{
case ACTION_PAD : /* Skip padding */
pofs + + ;
pofs + = 1 + packet [ pofs ] ;
break ;
case ACTION_EOT : /* EOT */
pofs = len ;
break ;
2011-05-05 09:10:38 +00:00
case ACTION_STATS :
/* short16 variable id,
int32 value */
{
pofs + + ;
short field = packet [ pofs + 1 ] + ( packet [ pofs ] < < 8 ) ;
int value = packet [ pofs + 5 ] + ( packet [ pofs + 4 ] < < 8 ) + ( packet [ pofs + 3 ] < < 16 ) + ( packet [ pofs + 2 ] < < 24 ) ;
pofs + = 6 ;
if ( instrumentation_file )
{
if ( ! i_f ) { if ( strcmp ( instrumentation_file , " - " ) ) i_f = fopen ( instrumentation_file , " a " ) ; else i_f = stdout ; }
if ( i_f ) fprintf ( i_f , " %ld:%08x:%d:%d \n " , time ( 0 ) , * ( unsigned int * ) & sender - > sa_data [ 0 ] , field , value ) ;
if ( i_f ) fflush ( i_f ) ;
}
}
break ;
2011-05-23 11:35:15 +00:00
case ACTION_DIGITALTELEGRAM :
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_DNAREQUESTS ) fprintf ( stderr , " In ACTION_DIGITALTELEGRAM \n " ) ;
2011-05-23 11:35:15 +00:00
{
2012-03-06 03:59:47 +00:00
// Unpack SMS message.
char emitterPhoneNumber [ 256 ] ;
char message [ 256 ] ;
pofs + + ;
/* char messageType = packet[pofs]; */
pofs + + ;
char emitterPhoneNumberLen = packet [ pofs ] ;
pofs + + ;
char messageLen = packet [ pofs ] ;
pofs + + ;
strncpy ( emitterPhoneNumber , ( const char * ) packet + pofs , emitterPhoneNumberLen ) ;
emitterPhoneNumber [ ( unsigned int ) emitterPhoneNumberLen ] = 0 ;
2011-05-26 04:55:59 +00:00
2012-03-06 03:59:47 +00:00
pofs + = emitterPhoneNumberLen ;
strncpy ( message , ( const char * ) packet + pofs , messageLen ) ;
message [ ( unsigned int ) messageLen ] = 0 ;
pofs + = messageLen ;
// Check if I'm the recipient
ofs = 0 ;
if ( findHlr ( hlr , & ofs , sid , did ) ) {
// Check transaction cache to see if message has already been delivered. If not,
// then deliver it now.
if ( ! isTransactionInCache ( transaction_id ) ) {
2012-03-01 03:06:36 +00:00
// Deliver SMS to android.
char amCommand [ 576 ] ; // 64 char + 2*256(max) char = 576
sprintf ( amCommand , " am broadcast -a org.servalproject.DT -e number \" %s \" -e content \" %s \" " , emitterPhoneNumber , message ) ;
if ( debug & DEBUG_DNAREQUESTS ) fprintf ( stderr , " Delivering DT message via intent: %s \n " , amCommand ) ;
runCommand ( amCommand ) ;
// Record in cache to prevent re-delivering the same message if a duplicate is received.
insertTransactionInCache ( transaction_id ) ;
}
2012-03-13 08:01:29 +00:00
char sid [ SID_STRLEN + 1 ] ;
respondSimple ( hlrSid ( hlr , ofs , sid ) , ACTION_OKAY , NULL , 0 , transaction_id , recvttl , sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2011-05-23 21:52:43 +00:00
}
2011-03-22 06:33:14 +00:00
}
break ;
2010-07-13 12:15:46 +00:00
case ACTION_SET :
ofs = 0 ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_DNAREQUESTS ) fprintf ( stderr , " Looking for hlr entries with sid='%s' / did='%s' \n " , sid , did ) ;
2011-04-27 02:47:26 +00:00
if ( ( ! sid ) | | ( ! sid [ 0 ] ) ) {
setReason ( " You can only set variables by SID " ) ;
2012-02-05 05:45:19 +00:00
return respondSimple ( NULL , ACTION_ERROR ,
( unsigned char * ) " SET requires authentication by SID " ,
0 , transaction_id , recvttl ,
2011-08-12 19:34:38 +00:00
sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2011-04-27 02:47:26 +00:00
}
2010-07-13 12:15:46 +00:00
while ( findHlr ( hlr , & ofs , sid , did ) )
{
2011-03-30 05:04:23 +00:00
int itemId , instance , start_offset , bytes , flags ;
unsigned char value [ 9000 ] , oldvalue [ 65536 ] ;
int oldr , oldl ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " findHlr found a match for writing at 0x%x \n " , ofs ) ;
if ( debug & DEBUG_HLR ) hlrDump ( hlr , ofs ) ;
2010-07-13 12:15:46 +00:00
/* XXX consider taking action on this HLR
( check PIN first depending on the action requested ) */
/* XXX Doesn't verify PIN authentication */
/* Get write request */
pofs + + ; rofs = pofs ;
if ( extractRequest ( packet , & pofs , len ,
& itemId , & instance , value ,
& start_offset , & bytes , & flags ) )
{
setReason ( " Could not extract ACTION_SET request " ) ;
return
2012-02-05 05:45:19 +00:00
respondSimple ( NULL , ACTION_ERROR ,
( unsigned char * ) " Mal-formed SET request " ,
0 , transaction_id , recvttl ,
2011-08-12 19:34:38 +00:00
sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2010-07-13 12:15:46 +00:00
}
/* Get the stored value */
oldl = 65536 ;
oldr = hlrGetVariable ( hlr , ofs , itemId , instance , oldvalue , & oldl ) ;
if ( oldr ) {
if ( flags = = SET_NOREPLACE ) {
oldl = 0 ;
} else {
setReason ( " Tried to SET_NOCREATE/SET_REPLACE a non-existing value " ) ;
return
respondSimple ( NULL , ACTION_ERROR ,
( unsigned char * ) " Cannot SET NOCREATE/REPLACE a value that does not exist " ,
2012-02-05 05:45:19 +00:00
0 , transaction_id , recvttl , sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2010-07-13 12:15:46 +00:00
}
} else {
if ( flags = = SET_NOREPLACE ) {
setReason ( " Tried to SET_NOREPLACE an existing value " ) ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_DNAREQUESTS ) dump ( " Existing value (in SET_NOREPLACE flagged request) " , oldvalue , oldl ) ;
2010-07-13 12:15:46 +00:00
return
respondSimple ( NULL , ACTION_ERROR ,
( unsigned char * ) " Cannot SET NOREPLACE; a value exists " ,
2012-02-05 05:45:19 +00:00
0 , transaction_id , recvttl , sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2010-07-13 12:15:46 +00:00
}
}
/* Replace the changed portion of the stored value */
if ( ( start_offset + bytes ) > oldl ) {
bzero ( & oldvalue [ oldl ] , start_offset + bytes - oldl ) ;
oldl = start_offset + bytes ;
}
bcopy ( & value [ 0 ] , & oldvalue [ start_offset ] , bytes ) ;
/* Write new value back */
if ( hlrSetVariable ( hlr , ofs , itemId , instance , oldvalue , oldl ) )
{
setReason ( " Failed to write variable " ) ;
return
2012-02-05 05:45:19 +00:00
respondSimple ( NULL , ACTION_ERROR ,
( unsigned char * ) " Failed to SET variable " ,
0 , transaction_id , recvttl ,
2011-08-12 19:34:38 +00:00
sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2010-07-13 12:15:46 +00:00
}
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) { fprintf ( stderr , " HLR after writing: \n " ) ; hlrDump ( hlr , ofs ) ; }
2010-07-13 12:15:46 +00:00
/* Reply that we wrote the fragment */
respondSimple ( sid , ACTION_WROTE , & packet [ rofs ] , 6 ,
2012-02-05 05:45:19 +00:00
transaction_id , recvttl ,
sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2010-07-13 12:15:46 +00:00
/* Advance to next record and keep searching */
if ( nextHlr ( hlr , & ofs ) ) break ;
}
break ;
case ACTION_GET :
2011-04-27 02:47:26 +00:00
{
/* Limit transfer size to MAX_DATA_BYTES, plus an allowance for variable packing. */
unsigned char data [ MAX_DATA_BYTES + 16 ] ;
int dlen = 0 ;
int sendDone = 0 ;
2011-03-30 05:04:23 +00:00
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) dump ( " Request bytes " , & packet [ pofs ] , 8 ) ;
2011-08-29 06:50:27 +00:00
pofs + + ;
int var_id = packet [ pofs ] ;
int instance = - 1 ;
if ( var_id & 0x80 ) instance = packet [ + + pofs ] ;
pofs + + ;
int offset = ( packet [ pofs ] < < 8 ) + packet [ pofs + 1 ] ; pofs + = 2 ;
2012-03-16 22:34:21 +00:00
# warning Defining SID here is masking the version passed in, which other stuff still expects to be visible? Also, does it need to be SID_STRLEN*2+1 to allow for byte->hex expansion? Or has SID_STRLEN been defined to take that into account?
2012-03-13 08:01:29 +00:00
char sid [ SID_STRLEN + 1 ] ;
2011-08-29 06:50:27 +00:00
char * hlr_sid = NULL ;
2011-10-05 22:57:04 +00:00
pofs + = 2 ;
2011-08-29 06:50:27 +00:00
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_DNAREQUESTS ) fprintf ( stderr , " Processing ACTION_GET (var_id=%02x, instance=%02x, pofs=0x%x, len=%d) \n " , var_id , instance , pofs , len ) ;
2010-07-13 12:15:46 +00:00
2011-04-27 02:47:26 +00:00
ofs = 0 ;
2012-03-16 22:34:21 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " Looking for hlr entries with sid='%s' / did='%s' \n " , ( sid & & sid [ 0 ] ) ? sid : " null " , did ? did : " null " ) ;
2011-04-27 02:47:26 +00:00
while ( 1 )
{
struct hlrentry_handle * h ;
// if an empty did was passed in, get results from all hlr records
if ( * sid | | * did ) {
if ( ! findHlr ( hlr , & ofs , sid , did ) ) break ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " findHlr found a match @ 0x%x \n " , ofs ) ;
2010-07-13 12:15:46 +00:00
}
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) hlrDump ( hlr , ofs ) ;
2011-04-27 02:47:26 +00:00
/* XXX consider taking action on this HLR
( check PIN first depending on the action requested ) */
/* Form a reply packet containing the requested data */
if ( instance = = 0xff ) instance = - 1 ;
/* Step through HLR to find any matching instances of the requested variable */
h = openhlrentry ( hlr , ofs ) ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " openhlrentry(hlr,%d) returned %p \n " , ofs , h ) ;
2011-04-27 02:47:26 +00:00
while ( h )
{
/* Is this the variable? */
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " considering var_id=%02x, instance=%02x \n " ,
2011-04-27 02:47:26 +00:00
h - > var_id , h - > var_instance ) ;
if ( h - > var_id = = var_id )
{
if ( h - > var_instance = = instance | | instance = = - 1 )
{
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " Sending matching variable value instance (instance #%d), value offset %d. \n " ,
2011-04-27 02:47:26 +00:00
h - > var_instance , offset ) ;
// only send each value when the *next* record is found, that way we can easily stamp the last response with DONE
if ( sendDone > 0 )
2012-02-05 05:45:19 +00:00
respondSimple ( hlr_sid , ACTION_DATA , data , dlen ,
transaction_id , recvttl , sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2011-04-27 02:47:26 +00:00
dlen = 0 ;
if ( packageVariableSegment ( data , & dlen , h , offset , MAX_DATA_BYTES + 16 ) )
return setReason ( " packageVariableSegment() failed . " ) ;
2012-03-13 08:01:29 +00:00
hlr_sid = hlrSid ( hlr , ofs , sid ) ;
2011-04-27 02:47:26 +00:00
sendDone + + ;
}
else
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " Ignoring variable instance %d (not %d) \n " ,
2011-04-27 02:47:26 +00:00
h - > var_instance , instance ) ;
}
else
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " Ignoring variable ID %d (not %d) \n " ,
2011-04-27 02:47:26 +00:00
h - > var_id , var_id ) ;
h = hlrentrygetent ( h ) ;
}
/* Advance to next record and keep searching */
if ( nextHlr ( hlr , & ofs ) ) break ;
}
2010-07-13 12:15:46 +00:00
if ( sendDone )
{
2011-04-27 02:47:26 +00:00
data [ dlen + + ] = ACTION_DONE ;
data [ dlen + + ] = sendDone & 0xff ;
2012-02-05 05:45:19 +00:00
respondSimple ( hlr_sid , ACTION_DATA , data , dlen , transaction_id ,
recvttl , sender , CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2010-07-13 12:15:46 +00:00
}
2011-08-10 13:38:59 +00:00
if ( gatewayspec & & ( var_id = = VAR_LOCATIONS ) & & did & & strlen ( did ) )
2011-05-06 03:16:04 +00:00
{
/* We are a gateway, so offer connection via the gateway as well */
unsigned char data [ MAX_DATA_BYTES + 16 ] ;
int dlen = 0 ;
struct hlrentry_handle fake ;
unsigned char uri [ 1024 ] ;
2011-05-16 07:28:25 +00:00
/* We use asterisk to provide the gateway service,
so we need to create a temporary extension in extensions . conf ,
ask asterisk to re - read extensions . conf , and then make sure it has
a functional SIP gateway .
*/
2011-05-23 21:52:43 +00:00
if ( ! asteriskObtainGateway ( sid , did , ( char * ) uri ) )
2011-05-16 07:28:25 +00:00
{
fake . value_len = strlen ( ( char * ) uri ) ;
fake . var_id = var_id ;
fake . value = uri ;
if ( packageVariableSegment ( data , & dlen , & fake , offset , MAX_DATA_BYTES + 16 ) )
return setReason ( " packageVariableSegment() of gateway URI failed . " ) ;
2012-03-13 08:01:29 +00:00
char sid [ SID_STRLEN + 1 ] ;
respondSimple ( hlrSid ( hlr , 0 , sid ) , ACTION_DATA , data , dlen ,
2012-02-05 05:45:19 +00:00
transaction_id , recvttl , sender ,
CRYPT_CIPHERED | CRYPT_SIGNED ) ;
2011-05-16 07:28:25 +00:00
}
else
{
/* Should we indicate the gateway is not available? */
}
2011-05-06 03:16:04 +00:00
}
2011-04-27 02:47:26 +00:00
}
2010-07-13 12:15:46 +00:00
break ;
default :
setReason ( " Asked to perform unsupported action " ) ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_PACKETFORMATS ) fprintf ( stderr , " Asked to perform unsipported action at Packet offset = 0x%x \n " , pofs ) ;
if ( debug & DEBUG_PACKETFORMATS ) dump ( " Packet " , packet , len ) ;
2012-01-08 18:00:23 +00:00
return WHY ( " Asked to perform unsupported action. " ) ;
2010-07-13 12:15:46 +00:00
}
}
}
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_HLR ) fprintf ( stderr , " Searched %d HLR entries. \n " , records_searched ) ;
2010-07-13 12:15:46 +00:00
return 0 ;
}
int respondSimple ( char * sid , int action , unsigned char * action_text , int action_len ,
2012-02-05 05:45:19 +00:00
unsigned char * transaction_id , int recvttl ,
struct sockaddr * recvaddr , int cryptoFlags )
2010-07-13 12:15:46 +00:00
{
unsigned char packet [ 8000 ] ;
int pl = 0 ;
int * packet_len = & pl ;
int packet_maxlen = 8000 ;
int i ;
2011-05-16 07:28:25 +00:00
/* XXX Complain about invalid crypto flags.
XXX We don ' t do anything with the crypto flags right now
XXX Other packet sending routines need this as well . */
2012-01-08 18:00:23 +00:00
if ( ! cryptoFlags ) return WHY ( " Crypto-flags not set. " ) ;
2011-05-16 07:28:25 +00:00
2010-07-13 12:15:46 +00:00
/* ACTION_ERROR is associated with an error message.
For syntactic simplicity , we do not require the respondSimple ( ) call to provide
the length of the error message . */
if ( action = = ACTION_ERROR ) {
action_len = strlen ( ( char * ) action_text ) ;
/* Make sure the error text isn't too long.
IF it is , trim it , as we still need to communicate the error */
if ( action_len > 255 ) action_len = 255 ;
}
/* Prepare the request packet */
2012-01-08 18:00:23 +00:00
if ( packetMakeHeader ( packet , 8000 , packet_len , transaction_id , cryptoFlags ) )
return WHY ( " packetMakeHeader() failed . " ) ;
2010-07-13 12:15:46 +00:00
if ( sid & & sid [ 0 ] )
{ if ( packetSetSid ( packet , 8000 , packet_len , sid ) )
return setReason ( " invalid SID in reply " ) ; }
else
{ if ( packetSetDid ( packet , 8000 , packet_len , " " ) )
return setReason ( " Could not set empty DID in reply " ) ; }
CHECK_PACKET_LEN ( 1 + 1 + action_len ) ;
packet [ ( * packet_len ) + + ] = action ;
if ( action = = ACTION_ERROR ) packet [ ( * packet_len ) + + ] = action_len ;
for ( i = 0 ; i < action_len ; i + + ) packet [ ( * packet_len ) + + ] = action_text [ i ] ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_DNARESPONSES ) dump ( " Simple response octets " , action_text , action_len ) ;
2010-07-13 12:15:46 +00:00
2012-02-05 05:45:19 +00:00
if ( packetFinalise ( packet , 8000 , recvttl , packet_len , cryptoFlags ) )
2012-01-08 18:00:23 +00:00
return WHY ( " packetFinalise() failed . " ) ;
2010-07-13 12:15:46 +00:00
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_DNARESPONSES ) fprintf ( stderr , " Sending response of %d bytes. \n " , * packet_len ) ;
2010-07-13 12:15:46 +00:00
2012-01-08 18:00:23 +00:00
if ( packetSendRequest ( REQ_REPLY , packet , * packet_len , NONBATCH , transaction_id , recvaddr , NULL ) )
return WHY ( " packetSendRequest() failed . " ) ;
2010-07-13 12:15:46 +00:00
return 0 ;
}
2011-08-08 14:41:46 +00:00
int createServerSocket ( )
{
struct sockaddr_in bind_addr ;
sock = socket ( PF_INET , SOCK_DGRAM , 0 ) ;
if ( sock < 0 ) {
fprintf ( stderr , " Could not create UDP socket. \n " ) ;
perror ( " socket " ) ;
exit ( - 3 ) ;
}
2012-02-23 01:29:06 +00:00
/* Automatically close socket on calls to exec().
This makes life easier when we restart with an exec after receiving
a bad signal . */
fcntl ( sock , F_SETFL ,
fcntl ( sock , F_GETFL , NULL ) | O_CLOEXEC ) ;
2011-08-08 14:41:46 +00:00
int TRUE = 1 ;
setsockopt ( sock , SOL_SOCKET , SO_BROADCAST , & TRUE , sizeof ( TRUE ) ) ;
2012-02-05 05:45:19 +00:00
errno = 0 ;
if ( setsockopt ( sock , IPPROTO_IP , IP_RECVTTL , & TRUE , sizeof ( TRUE ) ) < 0 )
perror ( " setsockopt(IP_RECVTTL) " ) ;
2011-08-08 14:41:46 +00:00
bind_addr . sin_family = AF_INET ;
bind_addr . sin_port = htons ( PORT_DNA ) ;
bind_addr . sin_addr . s_addr = htonl ( INADDR_ANY ) ;
if ( bind ( sock , ( struct sockaddr * ) & bind_addr , sizeof ( bind_addr ) ) ) {
fprintf ( stderr , " MP HLR server could not bind to UDP port %d \n " , PORT_DNA ) ;
perror ( " bind " ) ;
exit ( - 3 ) ;
}
return 0 ;
}
2011-12-22 11:28:18 +00:00
extern int sigIoFlag ;
extern int rhizome_server_socket ;
2011-08-08 14:41:46 +00:00
int simpleServerMode ( )
{
while ( 1 ) {
2011-08-12 19:34:38 +00:00
struct sockaddr recvaddr ;
2011-08-08 14:41:46 +00:00
socklen_t recvaddrlen = sizeof ( recvaddr ) ;
2011-12-22 11:28:18 +00:00
struct pollfd fds [ 128 ] ;
int fdcount ;
2011-08-08 14:41:46 +00:00
int len ;
2011-12-22 11:28:18 +00:00
int r ;
2011-08-08 14:41:46 +00:00
2012-03-04 22:57:31 +00:00
if ( servalShutdown ) servalShutdownCleanly ( ) ;
2011-08-08 14:41:46 +00:00
bzero ( ( void * ) & recvaddr , sizeof ( recvaddr ) ) ;
2011-12-22 11:28:18 +00:00
/* Get rhizome server started BEFORE populating fd list so that
the server ' s listen socket is in the list for poll ( ) */
if ( rhizome_datastore_path ) rhizome_server_poll ( ) ;
/* Get list of file descripters to watch */
fds [ 0 ] . fd = sock ; fds [ 0 ] . events = POLLIN ;
fdcount = 1 ;
rhizome_server_get_fds ( fds , & fdcount , 128 ) ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_IO ) {
2011-12-22 17:55:18 +00:00
printf ( " poll()ing file descriptors: " ) ;
{ int i ;
for ( i = 0 ; i < fdcount ; i + + ) { printf ( " %d " , fds [ i ] . fd ) ; } }
printf ( " \n " ) ;
}
2011-12-22 11:28:18 +00:00
/* Wait patiently for packets to arrive. */
if ( rhizome_datastore_path ) rhizome_server_poll ( ) ;
while ( ( r = poll ( fds , fdcount , 100000 ) ) < 1 ) {
if ( sigIoFlag ) { sigIoFlag = 0 ; break ; }
sleep ( 0 ) ;
2011-08-08 14:41:46 +00:00
}
2011-12-22 11:28:18 +00:00
if ( rhizome_datastore_path ) rhizome_server_poll ( ) ;
2012-02-05 05:45:19 +00:00
unsigned char buffer [ 16384 ] ;
int ttl = - 1 ; // unknown
2011-12-22 11:28:18 +00:00
if ( fds [ 0 ] . revents & POLLIN ) {
2012-02-05 05:45:19 +00:00
len = recvwithttl ( sock , buffer , sizeof ( buffer ) , & ttl , & recvaddr , & recvaddrlen ) ;
2011-12-22 11:28:18 +00:00
client_port = ( ( struct sockaddr_in * ) & recvaddr ) - > sin_port ;
client_addr = ( ( struct sockaddr_in * ) & recvaddr ) - > sin_addr ;
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_DNAREQUESTS ) fprintf ( stderr , " Received packet from %s:%d (len=%d). \n " , inet_ntoa ( client_addr ) , client_port , len ) ;
if ( debug & DEBUG_PACKETXFER ) dump ( " recvaddr " , ( unsigned char * ) & recvaddr , recvaddrlen ) ;
if ( debug & DEBUG_PACKETXFER ) dump ( " packet " , ( unsigned char * ) buffer , len ) ;
2011-12-22 11:28:18 +00:00
if ( dropPacketP ( len ) ) {
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_SIMULATION ) fprintf ( stderr , " Simulation mode: Dropped packet due to simulated link parameters. \n " ) ;
2011-12-22 11:28:18 +00:00
continue ;
}
/* Simple server mode doesn't really use interface numbers, so lie and say interface -1 */
2012-02-05 05:45:19 +00:00
if ( packetOk ( - 1 , buffer , len , NULL , ttl , & recvaddr , recvaddrlen , 1 ) ) {
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_PACKETFORMATS ) setReason ( " Ignoring invalid packet " ) ;
2011-12-22 11:28:18 +00:00
}
2012-01-10 05:26:40 +00:00
if ( debug & DEBUG_PACKETXFER ) fprintf ( stderr , " Finished processing packet, waiting for next one. \n " ) ;
2011-08-08 14:41:46 +00:00
}
}
return 0 ;
}
2012-02-15 13:08:23 +00:00
# ifdef DEBUG_MEM_ABUSE
unsigned char groundzero [ 65536 ] ;
2012-02-15 13:21:12 +00:00
int memabuseInitP = 0 ;
2012-02-15 13:08:23 +00:00
int memabuseInit ( )
{
2012-02-15 13:21:12 +00:00
if ( memabuseInitP ) {
fprintf ( stderr , " WARNING: memabuseInit() called more than once. \n " ) ;
return memabuseCheck ( ) ;
}
2012-02-15 13:08:23 +00:00
unsigned char * zero = ( unsigned char * ) 0 ;
int i ;
2012-02-15 13:21:12 +00:00
for ( i = 0 ; i < 65536 ; i + + ) {
groundzero [ i ] = zero [ i ] ;
printf ( " %04x \n " , i ) ;
}
memabuseInitP = 1 ;
2012-02-15 13:08:23 +00:00
return 0 ;
}
2012-02-15 13:21:12 +00:00
int _memabuseCheck ( const char * func , const char * file , const int line )
2012-02-15 13:08:23 +00:00
{
unsigned char * zero = ( unsigned char * ) 0 ;
int firstAddr = - 1 ;
int lastAddr = - 1 ;
int i ;
for ( i = 0 ; i < 65536 ; i + + ) if ( groundzero [ i ] ! = zero [ i ] ) {
lastAddr = i ;
if ( firstAddr = = - 1 ) firstAddr = i ;
}
if ( lastAddr > 0 ) {
fprintf ( stderr , " WARNING: Memory corruption in first 64KB of RAM detected. \n " ) ;
fprintf ( stderr , " Changed bytes exist in range 0x%04x - 0x%04x \n " , firstAddr , lastAddr ) ;
dump ( " Changed memory content " , & zero [ firstAddr ] , lastAddr - firstAddr + 1 ) ;
dump ( " Initial memory content " , & groundzero [ firstAddr ] , lastAddr - firstAddr + 1 ) ;
sleep ( 1 ) ;
} else {
fprintf ( stderr , " All's well at %s() %s:%d \n " , func , file , line ) ;
}
return 0 ;
}
# endif