2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								#!/usr/bin/env python  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								###############################################################################  
						 
					
						
							
								
									
										
										
										
											2019-02-22 16:30:16 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								#   Copyright (C) 2016-2019 Cortney T. Buffington, N0MJS <n0mjs@me.com>  
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								#  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#   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 3 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  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								###############################################################################  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								''' 
  
						 
					
						
							
								
									
										
										
										
											2019-02-22 16:27:58 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								This  program  does  very  little  on  its  own .  It  is  intended  to  be  used  as  a  module  
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								to  build  applications  on  top  of  the  HomeBrew  Repeater  Protocol .  By  itself ,  it  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								will  only  act  as  a  peer  or  master  for  the  systems  specified  in  its  configuration  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								file  ( usually  hblink . cfg ) .  It  is  ALWAYS  best  practice  to  ensure  that  this  program  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								works  stand - alone  before  troubleshooting  any  applications  that  use  it .  It  has  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								sufficient  logging  to  be  used  standalone  as  a  troubleshooting  application .  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								''' 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Specifig functions from modules we need  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  binascii  import  b2a_hex  as  ahex  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  binascii  import  a2b_hex  as  bhex  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  random  import  randint  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  hashlib  import  sha256 ,  sha1  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  hmac  import  new  as  hmac_new ,  compare_digest  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  time  import  time  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  collections  import  deque  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Twisted is pretty important, so I keep it separate  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  twisted . internet . protocol  import  DatagramProtocol ,  Factory ,  Protocol  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  twisted . protocols . basic  import  NetstringReceiver  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  twisted . internet  import  reactor ,  task  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Other files we pull from -- this is mostly for readability and segmentation  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  log  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  config  
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:36:32 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  const  import  *  
						 
					
						
							
								
									
										
										
										
											2019-01-04 15:32:13 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  dmr_utils3 . utils  import  int_id ,  bytes_4 ,  try_download ,  mk_id_dict  
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Imports for the reporting server  
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  pickle  
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								from  reporting_const  import  *  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# The module needs logging logging, but handlers, etc. are controlled by the parent  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  logging  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								logger  =  logging . getLogger ( __name__ )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Does anybody read this stuff? There's a PEP somewhere that says I should do this.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								__author__      =  ' Cortney T. Buffington, N0MJS '  
						 
					
						
							
								
									
										
										
										
											2019-03-05 19:01:07 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								__copyright__   =  ' Copyright (c) 2016-2019 Cortney T. Buffington, N0MJS and the K0USY Group '  
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								__credits__     =  ' Colin Durbridge, G4EML, Steve Zingman, N4IRS; Mike Zingman, N4IRR; Jonathan Naylor, G4KLX; Hans Barthen, DL5DI; Torsten Shultze, DG1HT '  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								__license__     =  ' GNU GPLv3 '  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								__maintainer__  =  ' Cort Buffington, N0MJS '  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								__email__       =  ' n0mjs@me.com '  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Global variables used whether we are a module or __main__  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								systems  =  { }  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Timed loop used for reporting HBP status  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  config_reports ( _config ,  _factory ) :  
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    def  reporting_loop ( _logger ,  _server ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . debug ( ' (GLOBAL) Periodic reporting loop started ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _server . send_config ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    logger . info ( ' (GLOBAL) HBlink TCP reporting server configured ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    report_server  =  _factory ( _config ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    report_server . clients  =  [ ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    reactor . listenTCP ( _config [ ' REPORTS ' ] [ ' REPORT_PORT ' ] ,  report_server ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    reporting  =  task . LoopingCall ( reporting_loop ,  logger ,  report_server ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    reporting . start ( _config [ ' REPORTS ' ] [ ' REPORT_INTERVAL ' ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  report_server 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Shut ourselves down gracefully by disconnecting from the masters and peers.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  hblink_handler ( _signal ,  _frame ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  system  in  systems : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        logger . info ( ' (GLOBAL) SHUTDOWN: DE-REGISTER SYSTEM:  %s ' ,  system ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        systems [ system ] . dereg ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Check a supplied ID against the ACL provided. Returns action (True|False) based  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# on matching and the action specified.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  acl_check ( _id ,  _acl ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    id  =  int_id ( _id ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  entry  in  _acl [ 1 ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  entry [ 0 ]  < =  id  < =  entry [ 1 ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return  _acl [ 0 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  not  _acl [ 0 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#************************************************  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#    OPENBRIDGE CLASS  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#************************************************  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  OPENBRIDGE ( DatagramProtocol ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  __init__ ( self ,  _name ,  _config ,  _report ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Define a few shortcuts to make the rest of the class more readable 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _CONFIG  =  _config 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _system  =  _name 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _report  =  _report 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _config  =  self . _CONFIG [ ' SYSTEMS ' ] [ self . _system ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _laststrid  =  deque ( [ ] ,  20 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  dereg ( self ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        logger . info ( ' ( %s ) is mode OPENBRIDGE. No De-Registration required, continuing shutdown ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  send_system ( self ,  _packet ) : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-09 09:51:04 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  _packet [ : 4 ]  ==  DMRD : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            #_packet = _packet[:11] + self._config['NETWORK_ID'] + _packet[15:] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            _packet  =  b ' ' . join ( [ _packet [ : 11 ] ,  self . _config [ ' NETWORK_ID ' ] ,  _packet [ 15 : ] ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            #_packet += hmac_new(self._config['PASSPHRASE'],_packet,sha1).digest() 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            _packet  =  b ' ' . join ( [ _packet ,  ( hmac_new ( self . _config [ ' PASSPHRASE ' ] , _packet , sha1 ) . digest ( ) ) ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            self . transport . write ( _packet ,  ( self . _config [ ' TARGET_IP ' ] ,  self . _config [ ' TARGET_PORT ' ] ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # logger.debug('(%s) TX Packet to OpenBridge %s:%s -- %s', self._system, self._config['TARGET_IP'], self._config['TARGET_PORT'], ahex(_packet)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        else : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-09 09:51:04 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            logger . error ( ' ( %s ) OpenBridge system was asked to send non DMRD packet:  %s ' ,  self . _system ,  _packet ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  dmrd_received ( self ,  _peer_id ,  _rf_src ,  _dst_id ,  _seq ,  _slot ,  _call_type ,  _frame_type ,  _dtype_vseq ,  _stream_id ,  _data ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        pass 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        #print(int_id(_peer_id), int_id(_rf_src), int_id(_dst_id), int_id(_seq), _slot, _call_type, _frame_type, repr(_dtype_vseq), int_id(_stream_id)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  datagramReceived ( self ,  _packet ,  _sockaddr ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Keep This Line Commented Unless HEAVILY Debugging! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        #logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_packet)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-09 09:51:04 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  _packet [ : 4 ]  ==  DMRD :     # DMRData -- encapsulated DMR data frame 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            _data  =  _packet [ : 53 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            _hash  =  _packet [ 53 : ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            _ckhs  =  hmac_new ( self . _config [ ' PASSPHRASE ' ] , _data , sha1 ) . digest ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  compare_digest ( _hash ,  _ckhs )  and  _sockaddr  ==  self . _config [ ' TARGET_SOCK ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _peer_id  =  _data [ 11 : 15 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _seq  =  _data [ 4 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _rf_src  =  _data [ 5 : 8 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _dst_id  =  _data [ 8 : 11 ] 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-04 15:32:13 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                _bits  =  _data [ 15 ] 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                _slot  =  2  if  ( _bits  &  0x80 )  else  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                #_call_type = 'unit' if (_bits & 0x40) else 'group' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  _bits  &  0x40 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _call_type  =  ' unit ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                elif  ( _bits  &  0x23 )  ==  0x23 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _call_type  =  ' vcsbk ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _call_type  =  ' group ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _frame_type  =  ( _bits  &  0x30 )  >>  4 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _dtype_vseq  =  ( _bits  &  0xF )  # data, 1=voice header, 2=voice terminator; voice, 0=burst A ... 5=burst F 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _stream_id  =  _data [ 16 : 20 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                #logger.debug('(%s) DMRD - Seqence: %s, RF Source: %s, Destination ID: %s', self._system, int_id(_seq), int_id(_rf_src), int_id(_dst_id)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # Sanity check for OpenBridge -- all calls must be on Slot 1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  _slot  !=  1 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logger . error ( ' ( %s ) OpenBridge packet discarded because it was not received on slot 1. SID:  %s , TGID  %s ' ,  self . _system ,  int_id ( _rf_src ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # ACL Processing 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  self . _CONFIG [ ' GLOBAL ' ] [ ' USE_ACL ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  not  acl_check ( _rf_src ,  self . _CONFIG [ ' GLOBAL ' ] [ ' SUB_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  _stream_id  not  in  self . _laststrid : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  FROM SUBSCRIBER  %s  BY GLOBAL ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _rf_src ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            self . _laststrid . append ( _stream_id ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  _slot  ==  1  and  not  acl_check ( _dst_id ,  self . _CONFIG [ ' GLOBAL ' ] [ ' TG1_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  _stream_id  not  in  self . _laststrid : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  ON TGID  %s  BY GLOBAL TS1 ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            self . _laststrid . append ( _stream_id ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  self . _config [ ' USE_ACL ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  not  acl_check ( _rf_src ,  self . _config [ ' SUB_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  _stream_id  not  in  self . _laststrid : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  FROM SUBSCRIBER  %s  BY SYSTEM ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _rf_src ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            self . _laststrid . append ( _stream_id ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  not  acl_check ( _dst_id ,  self . _config [ ' TG1_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  _stream_id  not  in  self . _laststrid : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  ON TGID  %s  BY SYSTEM ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            self . _laststrid . append ( _stream_id ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # Userland actions -- typically this is the function you subclass for an application 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                self . dmrd_received ( _peer_id ,  _rf_src ,  _dst_id ,  _seq ,  _slot ,  _call_type ,  _frame_type ,  _dtype_vseq ,  _stream_id ,  _data ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                logger . info ( ' ( %s ) OpenBridge HMAC failed, packet discarded - OPCODE:  %s  DATA:  %s  HMAC LENGTH:  %s  HMAC:  %s ' ,  self . _system ,  _packet [ : 4 ] ,  repr ( _packet [ : 53 ] ) ,  len ( _packet [ 53 : ] ) ,  repr ( _packet [ 53 : ] ) )  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#************************************************  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#     HB MASTER CLASS  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#************************************************  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  HBSYSTEM ( DatagramProtocol ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  __init__ ( self ,  _name ,  _config ,  _report ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Define a few shortcuts to make the rest of the class more readable 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _CONFIG  =  _config 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _system  =  _name 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _report  =  _report 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _config  =  self . _CONFIG [ ' SYSTEMS ' ] [ self . _system ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _laststrid1  =  ' ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _laststrid2  =  ' ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Define shortcuts and generic function names based on the type of system we are 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  self . _config [ ' MODE ' ]  ==  ' MASTER ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _peers  =  self . _CONFIG [ ' SYSTEMS ' ] [ self . _system ] [ ' PEERS ' ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . send_system  =  self . send_peers 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . maintenance_loop  =  self . master_maintenance_loop 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . datagramReceived  =  self . master_datagramReceived 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . dereg  =  self . master_dereg 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        elif  self . _config [ ' MODE ' ]  ==  ' PEER ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _stats  =  self . _config [ ' STATS ' ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . send_system  =  self . send_master 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . maintenance_loop  =  self . peer_maintenance_loop 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . datagramReceived  =  self . peer_datagramReceived 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . dereg  =  self . peer_dereg 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  startProtocol ( self ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Set up periodic loop for tracking pings from peers. Run every 'PING_TIME' seconds 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _system_maintenance  =  task . LoopingCall ( self . maintenance_loop ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _system_maintenance_loop  =  self . _system_maintenance . start ( self . _CONFIG [ ' GLOBAL ' ] [ ' PING_TIME ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Aliased in __init__ to maintenance_loop if system is a master 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  master_maintenance_loop ( self ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        logger . debug ( ' ( %s ) Master maintenance loop started ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        remove_list  =  [ ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  peer  in  self . _peers : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            _this_peer  =  self . _peers [ peer ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # Check to see if any of the peers have been quiet (no ping) longer than allowed 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  _this_peer [ ' LAST_PING ' ] + ( self . _CONFIG [ ' GLOBAL ' ] [ ' PING_TIME ' ] * self . _CONFIG [ ' GLOBAL ' ] [ ' MAX_MISSED ' ] )  <  time ( ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                remove_list . append ( peer ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  peer  in  remove_list : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            logger . info ( ' ( %s ) Peer  %s  ( %s ) has timed out and is being removed ' ,  self . _system ,  self . _peers [ peer ] [ ' CALLSIGN ' ] ,  self . _peers [ peer ] [ ' RADIO_ID ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # Remove any timed out peers from the configuration 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            del  self . _CONFIG [ ' SYSTEMS ' ] [ self . _system ] [ ' PEERS ' ] [ peer ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Aliased in __init__ to maintenance_loop if system is a peer 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  peer_maintenance_loop ( self ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        logger . debug ( ' ( %s ) Peer maintenance loop started ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  self . _stats [ ' PING_OUTSTANDING ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _stats [ ' NUM_OUTSTANDING ' ]  + =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # If we're not connected, zero out the stats and send a login request RPTL 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  self . _stats [ ' CONNECTION ' ]  !=  ' YES '  or  self . _stats [ ' NUM_OUTSTANDING ' ]  > =  self . _CONFIG [ ' GLOBAL ' ] [ ' MAX_MISSED ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _stats [ ' PINGS_SENT ' ]  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _stats [ ' PINGS_ACKD ' ]  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _stats [ ' NUM_OUTSTANDING ' ]  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _stats [ ' PING_OUTSTANDING ' ]  =  False 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _stats [ ' CONNECTION ' ]  =  ' RPTL_SENT ' 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            self . send_master ( b ' ' . join ( [ RPTL ,  self . _config [ ' RADIO_ID ' ] ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            logger . info ( ' ( %s ) Sending login request to master  %s : %s ' ,  self . _system ,  self . _config [ ' MASTER_IP ' ] ,  self . _config [ ' MASTER_PORT ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # If we are connected, sent a ping to the master and increment the counter 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  self . _stats [ ' CONNECTION ' ]  ==  ' YES ' : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            self . send_master ( b ' ' . join ( [ RPTPING ,  self . _config [ ' RADIO_ID ' ] ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            logger . debug ( ' ( %s ) RPTPING Sent to Master. Total Sent:  %s , Total Missed:  %s , Currently Outstanding:  %s ' ,  self . _system ,  self . _stats [ ' PINGS_SENT ' ] ,  self . _stats [ ' PINGS_SENT ' ]  -  self . _stats [ ' PINGS_ACKD ' ] ,  self . _stats [ ' NUM_OUTSTANDING ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _stats [ ' PINGS_SENT ' ]  + =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _stats [ ' PING_OUTSTANDING ' ]  =  True 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  send_peers ( self ,  _packet ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  _peer  in  self . _peers : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . send_peer ( _peer ,  _packet ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            #logger.debug('(%s) Packet sent to peer %s', self._system, self._peers[_peer]['RADIO_ID']) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  send_peer ( self ,  _peer ,  _packet ) : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-09 09:51:04 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  _packet [ : 4 ]  ==  DMRD : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 10:47:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            _packet  =  b ' ' . join ( [ _packet [ : 11 ] ,  _peer ,  _packet [ 15 : ] ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . transport . write ( _packet ,  self . _peers [ _peer ] [ ' SOCKADDR ' ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        #logger.debug('(%s) TX Packet to %s on port %s: %s', self._peers[_peer]['RADIO_ID'], self._peers[_peer]['IP'], self._peers[_peer]['PORT'], ahex(_packet)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  send_master ( self ,  _packet ) : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-09 09:51:04 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  _packet [ : 4 ]  ==  DMRD : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 10:47:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            _packet  =  b ' ' . join ( [ _packet [ : 11 ] ,  self . _config [ ' RADIO_ID ' ] ,  _packet [ 15 : ] ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        self . transport . write ( _packet ,  self . _config [ ' MASTER_SOCKADDR ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # logger.debug('(%s) TX Packet to %s:%s -- %s', self._system, self._config['MASTER_IP'], self._config['MASTER_PORT'], ahex(_packet)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  dmrd_received ( self ,  _peer_id ,  _rf_src ,  _dst_id ,  _seq ,  _slot ,  _call_type ,  _frame_type ,  _dtype_vseq ,  _stream_id ,  _data ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        pass 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  master_dereg ( self ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  _peer  in  self . _peers : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . send_peer ( _peer ,  MSTCL  +  _peer ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            logger . info ( ' ( %s ) De-Registration sent to Peer:  %s  ( %s ) ' ,  self . _system ,  self . _peers [ _peer ] [ ' CALLSIGN ' ] ,  self . _peers [ _peer ] [ ' RADIO_ID ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  peer_dereg ( self ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . send_master ( RPTCL  +  self . _config [ ' RADIO_ID ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        logger . info ( ' ( %s ) De-Registration sent to Master:  %s : %s ' ,  self . _system ,  self . _config [ ' MASTER_SOCKADDR ' ] [ 0 ] ,  self . _config [ ' MASTER_SOCKADDR ' ] [ 1 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Aliased in __init__ to datagramReceived if system is a master 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  master_datagramReceived ( self ,  _data ,  _sockaddr ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Keep This Line Commented Unless HEAVILY Debugging! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_data)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Extract the command, which is various length, all but one 4 significant characters -- RPTCL 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _command  =  _data [ : 4 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-09 09:51:04 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  _command  ==  DMRD :     # DMRData -- encapsulated DMR data frame 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            _peer_id  =  _data [ 11 : 15 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  _peer_id  in  self . _peers  \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        and  self . _peers [ _peer_id ] [ ' CONNECTION ' ]  ==  ' YES '  \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        and  self . _peers [ _peer_id ] [ ' SOCKADDR ' ]  ==  _sockaddr : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _seq  =  _data [ 4 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _rf_src  =  _data [ 5 : 8 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _dst_id  =  _data [ 8 : 11 ] 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 16:46:35 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                _bits  =  _data [ 15 ] 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                _slot  =  2  if  ( _bits  &  0x80 )  else  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                #_call_type = 'unit' if (_bits & 0x40) else 'group' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  _bits  &  0x40 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _call_type  =  ' unit ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                elif  ( _bits  &  0x23 )  ==  0x23 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _call_type  =  ' vcsbk ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _call_type  =  ' group ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _frame_type  =  ( _bits  &  0x30 )  >>  4 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _dtype_vseq  =  ( _bits  &  0xF )  # data, 1=voice header, 2=voice terminator; voice, 0=burst A ... 5=burst F 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _stream_id  =  _data [ 16 : 20 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                #logger.debug('(%s) DMRD - Seqence: %s, RF Source: %s, Destination ID: %s', self._system, int_id(_seq), int_id(_rf_src), int_id(_dst_id)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # ACL Processing 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  self . _CONFIG [ ' GLOBAL ' ] [ ' USE_ACL ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  not  acl_check ( _rf_src ,  self . _CONFIG [ ' GLOBAL ' ] [ ' SUB_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  self . _laststrid  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  FROM SUBSCRIBER  %s  BY GLOBAL ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _rf_src ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  _slot  ==  1 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                self . _laststrid1  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                self . _laststrid2  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  _slot  ==  1  and  not  acl_check ( _dst_id ,  self . _CONFIG [ ' GLOBAL ' ] [ ' TG1_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  self . _laststrid1  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  ON TGID  %s  BY GLOBAL TS1 ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            self . _laststrid1  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  _slot  ==  2  and  not  acl_check ( _dst_id ,  self . _CONFIG [ ' GLOBAL ' ] [ ' TG2_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  self . _laststrid2  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  ON TGID  %s  BY GLOBAL TS2 ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            self . _laststrid2  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  self . _config [ ' USE_ACL ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  not  acl_check ( _rf_src ,  self . _config [ ' SUB_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  self . _laststrid  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  FROM SUBSCRIBER  %s  BY SYSTEM ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _rf_src ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  _slot  ==  1 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                self . _laststrid1  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                self . _laststrid2  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  _slot  ==  1  and  not  acl_check ( _dst_id ,  self . _config [ ' TG1_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  self . _laststrid1  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  ON TGID  %s  BY SYSTEM TS1 ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            self . _laststrid1  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  _slot  ==  2  and  not  acl_check ( _dst_id ,  self . _config [ ' TG2_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  self . _laststrid2  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  ON TGID  %s  BY SYSTEM TS2 ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            self . _laststrid2  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # The basic purpose of a master is to repeat to the peers 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  self . _config [ ' REPEAT ' ]  ==  True : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    pkt  =  [ _data [ : 11 ] ,  ' ' ,  _data [ 15 : ] ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    for  _peer  in  self . _peers : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  _peer  !=  _peer_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            pkt [ 1 ]  =  _peer 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 16:46:35 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                            self . transport . write ( b ' ' . join ( pkt ) ,  self . _peers [ _peer ] [ ' SOCKADDR ' ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                            #logger.debug('(%s) Packet on TS%s from %s (%s) for destination ID %s repeated to peer: %s (%s) [Stream ID: %s]', self._system, _slot, self._peers[_peer_id]['CALLSIGN'], int_id(_peer_id), int_id(_dst_id), self._peers[_peer]['CALLSIGN'], int_id(_peer), int_id(_stream_id)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # Userland actions -- typically this is the function you subclass for an application 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                self . dmrd_received ( _peer_id ,  _rf_src ,  _dst_id ,  _seq ,  _slot ,  _call_type ,  _frame_type ,  _dtype_vseq ,  _stream_id ,  _data ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        elif  _command  ==  RPTL :     # RPTLogin -- a repeater wants to login 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            _peer_id  =  _data [ 4 : 8 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # Check to see if we've reached the maximum number of allowed peers 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  len ( self . _peers )  <  self . _config [ ' MAX_PEERS ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # Check for valid Radio ID 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  acl_check ( _peer_id ,  self . _CONFIG [ ' GLOBAL ' ] [ ' REG_ACL ' ] )  and  acl_check ( _peer_id ,  self . _config [ ' REG_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    # Build the configuration data strcuture for the peer 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    self . _peers . update ( { _peer_id :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' CONNECTION ' :  ' RPTL-RECEIVED ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' CONNECTED ' :  time ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' PINGS_RECEIVED ' :  0 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' LAST_PING ' :  time ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' SOCKADDR ' :  _sockaddr , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' IP ' :  _sockaddr [ 0 ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' PORT ' :  _sockaddr [ 1 ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' SALT ' :  randint ( 0 , 0xFFFFFFFF ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' RADIO_ID ' :  str ( int ( ahex ( _peer_id ) ,  16 ) ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' CALLSIGN ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' RX_FREQ ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' TX_FREQ ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' TX_POWER ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' COLORCODE ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' LATITUDE ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' LONGITUDE ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' HEIGHT ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' LOCATION ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' DESCRIPTION ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' SLOTS ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' URL ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' SOFTWARE_ID ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ' PACKAGE_ID ' :  ' ' , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    } } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logger . info ( ' ( %s ) Repeater Logging in with Radio ID:  %s ,  %s : %s ' ,  self . _system ,  int_id ( _peer_id ) ,  _sockaddr [ 0 ] ,  _sockaddr [ 1 ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-04 15:32:13 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    _salt_str  =  bytes_4 ( self . _peers [ _peer_id ] [ ' SALT ' ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    self . send_peer ( _peer_id ,  b ' ' . join ( [ RPTACK ,  _salt_str ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    self . _peers [ _peer_id ] [ ' CONNECTION ' ]  =  ' CHALLENGE_SENT ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logger . info ( ' ( %s ) Sent Challenge Response to  %s  for login:  %s ' ,  self . _system ,  int_id ( _peer_id ) ,  self . _peers [ _peer_id ] [ ' SALT ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                else : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    self . transport . write ( b ' ' . join ( [ MSTNAK ,  _peer_id ] ) ,  _sockaddr ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    logger . warning ( ' ( %s ) Invalid Login from Radio ID:  %s  Denied by Registation ACL ' ,  self . _system ,  int_id ( _peer_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                self . transport . write ( b ' ' . join ( [ MSTNAK ,  _peer_id ] ) ,  _sockaddr ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                logger . warning ( ' ( %s ) Registration denied from Radio ID:  %s  Maximum number of peers exceeded ' ,  self . _system ,  int_id ( _peer_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        elif  _command  ==  RPTK :     # Repeater has answered our login challenge 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            _peer_id  =  _data [ 4 : 8 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  _peer_id  in  self . _peers  \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        and  self . _peers [ _peer_id ] [ ' CONNECTION ' ]  ==  ' CHALLENGE_SENT '  \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        and  self . _peers [ _peer_id ] [ ' SOCKADDR ' ]  ==  _sockaddr : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _this_peer  =  self . _peers [ _peer_id ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _this_peer [ ' LAST_PING ' ]  =  time ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _sent_hash  =  _data [ 8 : ] 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-04 15:32:13 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                _salt_str  =  bytes_4 ( _this_peer [ ' SALT ' ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                _calc_hash  =  bhex ( sha256 ( _salt_str + self . _config [ ' PASSPHRASE ' ] ) . hexdigest ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  _sent_hash  ==  _calc_hash : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' CONNECTION ' ]  =  ' WAITING_CONFIG ' 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    self . send_peer ( _peer_id ,  b ' ' . join ( [ RPTACK ,  _peer_id ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    logger . info ( ' ( %s ) Peer  %s  has completed the login exchange successfully ' ,  self . _system ,  _this_peer [ ' RADIO_ID ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logger . info ( ' ( %s ) Peer  %s  has FAILED the login exchange successfully ' ,  self . _system ,  _this_peer [ ' RADIO_ID ' ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    self . transport . write ( b ' ' . join ( [ MSTNAK ,  _peer_id ] ) ,  _sockaddr ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    del  self . _peers [ _peer_id ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                self . transport . write ( b ' ' . join ( [ MSTNAK ,  _peer_id ] ) ,  _sockaddr ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                logger . warning ( ' ( %s ) Login challenge from Radio ID that has not logged in:  %s ' ,  self . _system ,  int_id ( _peer_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        elif  _command  ==  RPTC :     # Repeater is sending it's configuraiton OR disconnecting 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  _data [ : 5 ]  ==  RPTCL :     # Disconnect command 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _peer_id  =  _data [ 5 : 9 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  _peer_id  in  self . _peers  \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            and  self . _peers [ _peer_id ] [ ' CONNECTION ' ]  ==  ' YES '  \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            and  self . _peers [ _peer_id ] [ ' SOCKADDR ' ]  ==  _sockaddr : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logger . info ( ' ( %s ) Peer is closing down:  %s  ( %s ) ' ,  self . _system ,  self . _peers [ _peer_id ] [ ' CALLSIGN ' ] ,  int_id ( _peer_id ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    self . transport . write ( b ' ' . join ( [ MSTNAK ,  _peer_id ] ) ,  _sockaddr ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    del  self . _peers [ _peer_id ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _peer_id  =  _data [ 4 : 8 ]       # Configure Command 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  _peer_id  in  self . _peers  \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            and  self . _peers [ _peer_id ] [ ' CONNECTION ' ]  ==  ' WAITING_CONFIG '  \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            and  self . _peers [ _peer_id ] [ ' SOCKADDR ' ]  ==  _sockaddr : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer  =  self . _peers [ _peer_id ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' CONNECTION ' ]  =  ' YES ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' CONNECTED ' ]  =  time ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' LAST_PING ' ]  =  time ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' CALLSIGN ' ]  =  _data [ 8 : 16 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' RX_FREQ ' ]  =  _data [ 16 : 25 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' TX_FREQ ' ]  =   _data [ 25 : 34 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' TX_POWER ' ]  =  _data [ 34 : 36 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' COLORCODE ' ]  =  _data [ 36 : 38 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' LATITUDE ' ]  =  _data [ 38 : 46 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' LONGITUDE ' ]  =  _data [ 46 : 55 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' HEIGHT ' ]  =  _data [ 55 : 58 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' LOCATION ' ]  =  _data [ 58 : 78 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' DESCRIPTION ' ]  =  _data [ 78 : 97 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' SLOTS ' ]  =  _data [ 97 : 98 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' URL ' ]  =  _data [ 98 : 222 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' SOFTWARE_ID ' ]  =  _data [ 222 : 262 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _this_peer [ ' PACKAGE_ID ' ]  =  _data [ 262 : 302 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    self . send_peer ( _peer_id ,  b ' ' . join ( [ RPTACK ,  _peer_id ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    logger . info ( ' ( %s ) Peer  %s  ( %s ) has sent repeater configuration ' ,  self . _system ,  _this_peer [ ' CALLSIGN ' ] ,  _this_peer [ ' RADIO_ID ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                else : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    self . transport . write ( b ' ' . join ( [ MSTNAK ,  _peer_id ] ) ,  _sockaddr ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    logger . warning ( ' ( %s ) Peer info from Radio ID that has not logged in:  %s ' ,  self . _system ,  int_id ( _peer_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        elif  _command  ==  RPTP :     # RPTPing -- peer is pinging us 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _peer_id  =  _data [ 7 : 11 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  _peer_id  in  self . _peers  \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            and  self . _peers [ _peer_id ] [ ' CONNECTION ' ]  ==  " YES "  \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            and  self . _peers [ _peer_id ] [ ' SOCKADDR ' ]  ==  _sockaddr : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    self . _peers [ _peer_id ] [ ' PINGS_RECEIVED ' ]  + =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    self . _peers [ _peer_id ] [ ' LAST_PING ' ]  =  time ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    self . send_peer ( _peer_id ,  b ' ' . join ( [ MSTPONG ,  _peer_id ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    logger . debug ( ' ( %s ) Received and answered RPTPING from peer  %s  ( %s ) ' ,  self . _system ,  self . _peers [ _peer_id ] [ ' CALLSIGN ' ] ,  int_id ( _peer_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                else : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    self . transport . write ( b ' ' . join ( [ MSTNAK ,  _peer_id ] ) ,  _sockaddr ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    logger . warning ( ' ( %s ) Ping from Radio ID that is not logged in:  %s ' ,  self . _system ,  int_id ( _peer_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            logger . error ( ' ( %s ) Unrecognized command. Raw HBP PDU:  %s ' ,  self . _system ,  ahex ( _data ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Aliased in __init__ to datagramReceived if system is a peer 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  peer_datagramReceived ( self ,  _data ,  _sockaddr ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Keep This Line Commented Unless HEAVILY Debugging! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_data)) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Validate that we receveived this packet from the master - security check! 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  self . _config [ ' MASTER_SOCKADDR ' ]  ==  _sockaddr : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            # Extract the command, which is various length, but only 4 significant characters 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            _command  =  _data [ : 4 ] 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-09 09:51:04 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if    _command  ==  DMRD :     # DMRData -- encapsulated DMR data frame 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                _peer_id  =  _data [ 11 : 15 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  self . _config [ ' LOOSE ' ]  or  _peer_id  ==  self . _config [ ' RADIO_ID ' ] :  # Validate the Radio_ID unless using loose validation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _seq  =  _data [ 4 : 5 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _rf_src  =  _data [ 5 : 8 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _dst_id  =  _data [ 8 : 11 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _bits  =  _data [ 15 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _slot  =  2  if  ( _bits  &  0x80 )  else  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    #_call_type = 'unit' if (_bits & 0x40) else 'group' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  _bits  &  0x40 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        _call_type  =  ' unit ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    elif  ( _bits  &  0x23 )  ==  0x23 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        _call_type  =  ' vcsbk ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        _call_type  =  ' group ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _frame_type  =  ( _bits  &  0x30 )  >>  4 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _dtype_vseq  =  ( _bits  &  0xF )  # data, 1=voice header, 2=voice terminator; voice, 0=burst A ... 5=burst F 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _stream_id  =  _data [ 16 : 20 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    #logger.debug('(%s) DMRD - Sequence: %s, RF Source: %s, Destination ID: %s', self._system, int_id(_seq), int_id(_rf_src), int_id(_dst_id)) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-09 09:51:04 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    # ACL Processing 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  self . _CONFIG [ ' GLOBAL ' ] [ ' USE_ACL ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  not  acl_check ( _rf_src ,  self . _CONFIG [ ' GLOBAL ' ] [ ' SUB_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  self . _laststrid  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                logger . debug ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  FROM SUBSCRIBER  %s  BY GLOBAL ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _rf_src ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                if  _slot  ==  1 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                    self . _laststrid1  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                    self . _laststrid2  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  _slot  ==  1  and  not  acl_check ( _dst_id ,  self . _CONFIG [ ' GLOBAL ' ] [ ' TG1_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  self . _laststrid1  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                logger . debug ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  ON TGID  %s  BY GLOBAL TS1 ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                self . _laststrid1  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  _slot  ==  2  and  not  acl_check ( _dst_id ,  self . _CONFIG [ ' GLOBAL ' ] [ ' TG2_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  self . _laststrid2  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                logger . debug ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  ON TGID  %s  BY GLOBAL TS2 ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                self . _laststrid2  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  self . _config [ ' USE_ACL ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  not  acl_check ( _rf_src ,  self . _config [ ' SUB_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  self . _laststrid  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                logger . debug ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  FROM SUBSCRIBER  %s  BY SYSTEM ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _rf_src ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                if  _slot  ==  1 : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                    self . _laststrid1  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                    self . _laststrid2  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  _slot  ==  1  and  not  acl_check ( _dst_id ,  self . _config [ ' TG1_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  self . _laststrid1  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                logger . debug ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  ON TGID  %s  BY SYSTEM TS1 ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                self . _laststrid1  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  _slot  ==  2  and  not  acl_check ( _dst_id ,  self . _config [ ' TG2_ACL ' ] ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            if  self . _laststrid2  !=  _stream_id : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                logger . debug ( ' ( %s ) CALL DROPPED WITH STREAM ID  %s  ON TGID  %s  BY SYSTEM TS2 ACL ' ,  self . _system ,  int_id ( _stream_id ) ,  int_id ( _dst_id ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                self . _laststrid2  =  _stream_id 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    # Userland actions -- typically this is the function you subclass for an application 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    self . dmrd_received ( _peer_id ,  _rf_src ,  _dst_id ,  _seq ,  _slot ,  _call_type ,  _frame_type ,  _dtype_vseq ,  _stream_id ,  _data ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            elif  _command  ==  MSTN :     # Actually MSTNAK -- a NACK from the master 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _peer_id  =  _data [ 6 : 10 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  self . _config [ ' LOOSE ' ]  or  _peer_id  ==  self . _config [ ' RADIO_ID ' ] :  # Validate the Radio_ID unless using loose validation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logger . warning ( ' ( %s ) MSTNAK Received. Resetting connection to the Master. ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    self . _stats [ ' CONNECTION ' ]  =  ' NO '  # Disconnect ourselves and re-register 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    self . _stats [ ' CONNECTED ' ]  =  time ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            elif  _command  ==  RPTA :     # Actually RPTACK -- an ACK from the master 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                # Depending on the state, an RPTACK means different things, in each clause, we check and/or set the state 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  self . _stats [ ' CONNECTION ' ]  ==  ' RPTL_SENT ' :  # If we've sent a login request... 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _login_int32  =  _data [ 6 : 10 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logger . info ( ' ( %s ) Repeater Login ACK Received with 32bit ID:  %s ' ,  self . _system ,  int_id ( _login_int32 ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    _pass_hash  =  sha256 ( b ' ' . join ( [ _login_int32 ,  self . _config [ ' PASSPHRASE ' ] ] ) ) . hexdigest ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    _pass_hash  =  bhex ( _pass_hash ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    self . send_master ( b ' ' . join ( [ RPTK ,  self . _config [ ' RADIO_ID ' ] ,  _pass_hash ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                    self . _stats [ ' CONNECTION ' ]  =  ' AUTHENTICATED ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                elif  self . _stats [ ' CONNECTION ' ]  ==  ' AUTHENTICATED ' :  # If we've sent the login challenge... 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _peer_id  =  _data [ 6 : 10 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  self . _config [ ' LOOSE ' ]  or  _peer_id  ==  self . _config [ ' RADIO_ID ' ] :  # Validate the Radio_ID unless using loose validation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        logger . info ( ' ( %s ) Repeater Authentication Accepted ' ,  self . _system ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                        _config_packet  =   b ' ' . join ( [ \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' RADIO_ID ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' CALLSIGN ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' RX_FREQ ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' TX_FREQ ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' TX_POWER ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' COLORCODE ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' LATITUDE ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' LONGITUDE ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' HEIGHT ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' LOCATION ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' DESCRIPTION ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' SLOTS ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' URL ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' SOFTWARE_ID ' ] , \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                              self . _config [ ' PACKAGE_ID ' ] \
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                          ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        self . send_master ( b ' ' . join ( [ RPTC ,  _config_packet ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                        self . _stats [ ' CONNECTION ' ]  =  ' CONFIG-SENT ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        logger . info ( ' ( %s ) Repeater Configuration Sent ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        self . _stats [ ' CONNECTION ' ]  =  ' NO ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        logger . error ( ' ( %s ) Master ACK Contained wrong ID - Connection Reset ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                elif  self . _stats [ ' CONNECTION ' ]  ==  ' CONFIG-SENT ' :  # If we've sent out configuration to the master 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _peer_id  =  _data [ 6 : 10 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  self . _config [ ' LOOSE ' ]  or  _peer_id  ==  self . _config [ ' RADIO_ID ' ] :  # Validate the Radio_ID unless using loose validation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        logger . info ( ' ( %s ) Repeater Configuration Accepted ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        if  self . _config [ ' OPTIONS ' ] : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                            self . send_master ( b ' ' . join ( [ RPTO ,  self . _config [ ' RADIO_ID ' ] ,  self . _config [ ' OPTIONS ' ] ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								                            self . _stats [ ' CONNECTION ' ]  =  ' OPTIONS-SENT ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) Sent options: ( %s ) ' ,  self . _system ,  self . _config [ ' OPTIONS ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            self . _stats [ ' CONNECTION ' ]  =  ' YES ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            self . _stats [ ' CONNECTED ' ]  =  time ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                            logger . info ( ' ( %s ) Connection to Master Completed ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        self . _stats [ ' CONNECTION ' ]  =  ' NO ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        logger . error ( ' ( %s ) Master ACK Contained wrong ID - Connection Reset ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                elif  self . _stats [ ' CONNECTION ' ]  ==  ' OPTIONS-SENT ' :  # If we've sent out options to the master 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _peer_id  =  _data [ 6 : 10 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  self . _config [ ' LOOSE ' ]  or  _peer_id  ==  self . _config [ ' RADIO_ID ' ] :  # Validate the Radio_ID unless using loose validation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        logger . info ( ' ( %s ) Repeater Options Accepted ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        self . _stats [ ' CONNECTION ' ]  =  ' YES ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        self . _stats [ ' CONNECTED ' ]  =  time ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        logger . info ( ' ( %s ) Connection to Master Completed with options ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        self . _stats [ ' CONNECTION ' ]  =  ' NO ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        logger . error ( ' ( %s ) Master ACK Contained wrong ID - Connection Reset ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            elif  _command  ==  MSTP :     # Actually MSTPONG -- a reply to RPTPING (send by peer) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _peer_id  =  _data [ 7 : 11 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  self . _config [ ' LOOSE ' ]  or  _peer_id  ==  self . _config [ ' RADIO_ID ' ] :  # Validate the Radio_ID unless using loose validation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    self . _stats [ ' PING_OUTSTANDING ' ]  =  False 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    self . _stats [ ' NUM_OUTSTANDING ' ]  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    self . _stats [ ' PINGS_ACKD ' ]  + =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logger . debug ( ' ( %s ) MSTPONG Received. Pongs Since Connected:  %s ' ,  self . _system ,  self . _stats [ ' PINGS_ACKD ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            elif  _command  ==  MSTC :     # Actually MSTCL -- notify us the master is closing down 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _peer_id  =  _data [ 5 : 9 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  self . _config [ ' LOOSE ' ]  or  _peer_id  ==  self . _config [ ' RADIO_ID ' ] :  # Validate the Radio_ID unless using loose validation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    self . _stats [ ' CONNECTION ' ]  =  ' NO ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    logger . info ( ' ( %s ) MSTCL Recieved ' ,  self . _system ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                logger . error ( ' ( %s ) Received an invalid command in packet:  %s ' ,  self . _system ,  ahex ( _data ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Socket-based reporting section  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  report ( NetstringReceiver ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  __init__ ( self ,  factory ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _factory  =  factory 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  connectionMade ( self ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _factory . clients . append ( self ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        logger . info ( ' (REPORT) HBlink reporting client connected:  %s ' ,  self . transport . getPeer ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  connectionLost ( self ,  reason ) : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        logger . info ( ' (REPORT) HBlink reporting client disconnected:  %s ' ,  self . transport . getPeer ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        self . _factory . clients . remove ( self ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  stringReceived ( self ,  data ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . process_message ( data ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  process_message ( self ,  _message ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        opcode  =  _message [ : 1 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  opcode  ==  REPORT_OPCODES [ ' CONFIG_REQ ' ] : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            logger . info ( ' (REPORT) HBlink reporting client sent  \' CONFIG_REQ \' :  %s ' ,  self . transport . getPeer ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            self . send_config ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        else : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            logger . error ( ' (REPORT) got unknown opcode ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  reportFactory ( Factory ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  __init__ ( self ,  config ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _config  =  config 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  buildProtocol ( self ,  addr ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( addr . host )  in  self . _config [ ' REPORTS ' ] [ ' REPORT_CLIENTS ' ]  or  ' * '  in  self . _config [ ' REPORTS ' ] [ ' REPORT_CLIENTS ' ] : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            logger . debug ( ' (REPORT) Permitting report server connection attempt from:  %s : %s ' ,  addr . host ,  addr . port ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            return  report ( self ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        else : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            logger . error ( ' (REPORT) Invalid report server connection attempt from:  %s : %s ' ,  addr . host ,  addr . port ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            return  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  send_clients ( self ,  _message ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  client  in  self . clients : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            client . sendString ( _message ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  send_config ( self ) : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-04 15:32:13 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        serialized  =  pickle . dumps ( self . _config [ ' SYSTEMS ' ] ,  protocol = 2 )  #.decode('utf-8', errors='ignore') #pickle.HIGHEST_PROTOCOL) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        self . send_clients ( b ' ' . join ( [ REPORT_OPCODES [ ' CONFIG_SND ' ] ,  serialized ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# ID ALIAS CREATION  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# Download  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								def  mk_aliases ( _config ) :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  _config [ ' ALIASES ' ] [ ' TRY_DOWNLOAD ' ]  ==  True : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Try updating peer aliases file 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        result  =  try_download ( _config [ ' ALIASES ' ] [ ' PATH ' ] ,  _config [ ' ALIASES ' ] [ ' PEER_FILE ' ] ,  _config [ ' ALIASES ' ] [ ' PEER_URL ' ] ,  _config [ ' ALIASES ' ] [ ' STALE_TIME ' ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        logger . info ( ' (GLOBAL)  %s ' ,  result ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        # Try updating subscriber aliases file 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        result  =  try_download ( _config [ ' ALIASES ' ] [ ' PATH ' ] ,  _config [ ' ALIASES ' ] [ ' SUBSCRIBER_FILE ' ] ,  _config [ ' ALIASES ' ] [ ' SUBSCRIBER_URL ' ] ,  _config [ ' ALIASES ' ] [ ' STALE_TIME ' ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        logger . info ( ' (GLOBAL)  %s ' ,  result ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Make Dictionaries 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    peer_ids  =  mk_id_dict ( _config [ ' ALIASES ' ] [ ' PATH ' ] ,  _config [ ' ALIASES ' ] [ ' PEER_FILE ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  peer_ids : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        logger . info ( ' (GLOBAL) ID ALIAS MAPPER: peer_ids dictionary is available ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    subscriber_ids  =  mk_id_dict ( _config [ ' ALIASES ' ] [ ' PATH ' ] ,  _config [ ' ALIASES ' ] [ ' SUBSCRIBER_FILE ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  subscriber_ids : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        logger . info ( ' (GLOBAL) ID ALIAS MAPPER: subscriber_ids dictionary is available ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    talkgroup_ids  =  mk_id_dict ( _config [ ' ALIASES ' ] [ ' PATH ' ] ,  _config [ ' ALIASES ' ] [ ' TGID_FILE ' ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  talkgroup_ids : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        logger . info ( ' (GLOBAL) ID ALIAS MAPPER: talkgroup_ids dictionary is available ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  peer_ids ,  subscriber_ids ,  talkgroup_ids 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#************************************************  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#      MAIN PROGRAM LOOP STARTS HERE  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								#************************************************  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								if  __name__  ==  ' __main__ ' :  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Python modules we need 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    import  argparse 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    import  sys 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    import  os 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    import  signal 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Change the current directory to the location of the application 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    os . chdir ( os . path . dirname ( os . path . realpath ( sys . argv [ 0 ] ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # CLI argument parser - handles picking up the config file from the command line, and sending a "help" message 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    parser  =  argparse . ArgumentParser ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    parser . add_argument ( ' -c ' ,  ' --config ' ,  action = ' store ' ,  dest = ' CONFIG_FILE ' ,  help = ' /full/path/to/config.file (usually hblink.cfg) ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    parser . add_argument ( ' -l ' ,  ' --logging ' ,  action = ' store ' ,  dest = ' LOG_LEVEL ' ,  help = ' Override config file logging level. ' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    cli_args  =  parser . parse_args ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Ensure we have a path for the config file, if one wasn't specified, then use the execution directory 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  not  cli_args . CONFIG_FILE : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        cli_args . CONFIG_FILE  =  os . path . dirname ( os . path . abspath ( __file__ ) ) + ' /hblink.cfg ' 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Call the external routine to build the configuration dictionary 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    CONFIG  =  config . build_config ( cli_args . CONFIG_FILE ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Call the external routing to start the system logger 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  cli_args . LOG_LEVEL : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        CONFIG [ ' LOGGER ' ] [ ' LOG_LEVEL ' ]  =  cli_args . LOG_LEVEL 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    logger  =  log . config_logging ( CONFIG [ ' LOGGER ' ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-03-05 19:01:07 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    logger . info ( ' \n \n Copyright (c) 2013, 2014, 2015, 2016, 2018, 2019 \n \t The Regents of the K0USY Group. All rights reserved. \n ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    logger . debug ( ' (GLOBAL) Logging system started, anything from here on gets logged ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-04 15:32:13 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    # Set up the signal handler 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  sig_handler ( _signal ,  _frame ) : 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        logger . info ( ' (GLOBAL) SHUTDOWN: HBLINK IS TERMINATING WITH SIGNAL  %s ' ,  str ( _signal ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        hblink_handler ( _signal ,  _frame ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        logger . info ( ' (GLOBAL) SHUTDOWN: ALL SYSTEM HANDLERS EXECUTED - STOPPING REACTOR ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        reactor . stop ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # Set signal handers so that we can gracefully exit if need be 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  sig  in  [ signal . SIGTERM ,  signal . SIGINT ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        signal . signal ( sig ,  sig_handler ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    peer_ids ,  subscriber_ids ,  talkgroup_ids  =  mk_aliases ( CONFIG ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # INITIALIZE THE REPORTING LOOP 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  CONFIG [ ' REPORTS ' ] [ ' REPORT ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        report_server  =  config_reports ( CONFIG ,  reportFactory ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        report_server  =  None 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        logger . info ( ' (REPORT) TCP Socket reporting not configured ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # HBlink instance creation 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    logger . info ( ' (GLOBAL) HBlink  \' HBlink.py \'  -- SYSTEM STARTING... ' ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    for  system  in  CONFIG [ ' SYSTEMS ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  CONFIG [ ' SYSTEMS ' ] [ system ] [ ' ENABLED ' ] : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  CONFIG [ ' SYSTEMS ' ] [ system ] [ ' MODE ' ]  ==  ' OPENBRIDGE ' : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                systems [ system ]  =  OPENBRIDGE ( system ,  CONFIG ,  report_server ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                systems [ system ]  =  HBSYSTEM ( system ,  CONFIG ,  report_server ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            reactor . listenUDP ( CONFIG [ ' SYSTEMS ' ] [ system ] [ ' PORT ' ] ,  systems [ system ] ,  interface = CONFIG [ ' SYSTEMS ' ] [ system ] [ ' IP ' ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-07 09:44:36 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            logger . debug ( ' (GLOBAL)  %s  instance created:  %s ,  %s ' ,  CONFIG [ ' SYSTEMS ' ] [ system ] [ ' MODE ' ] ,  system ,  systems [ system ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-04 15:32:13 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-12-27 14:31:08 -06:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    reactor . run ( )