diff --git a/ambe_audio.py b/ambe_audio.py index 9186963..b9ed98b 100755 --- a/ambe_audio.py +++ b/ambe_audio.py @@ -29,7 +29,7 @@ from bitstring import BitArray import sys, socket, ConfigParser, thread, traceback import cPickle as pickle -from dmrlink import IPSC, systems +from dmrlink import IPSC, mk_ipsc_systems, systems, reportFactory, build_aliases, config_reports from dmr_utils.utils import int_id, hex_str_3, hex_str_4, get_alias, get_info from time import time, sleep, clock, localtime, strftime @@ -47,12 +47,12 @@ __email__ = 'n0mjs@me.com' try: - from ipsc.ipsc_const import * + from DMRlink.ipsc_const import * except ImportError: sys.exit('IPSC constants file not found or invalid') try: - from ipsc.ipsc_mask import * + from DMRlink.ipsc_mask import * except ImportError: sys.exit('IPSC mask values file not found or invalid') @@ -93,8 +93,8 @@ class ambeIPSC(IPSC): #_d = None ###### DEBUGDEBUGDEBUG - def __init__(self, _name, _config, _logger): - IPSC.__init__(self, _name, _config, _logger) + def __init__(self, _name, _config, _logger, _report): + IPSC.__init__(self, _name, _config, _logger, _report) self.CALL_DATA = [] # @@ -622,13 +622,12 @@ def get_subscriber_info(_src_sub): if __name__ == '__main__': import argparse - import os import sys + import os import signal - from dmr_utils.utils import try_download, mk_id_dict - import dmrlink_log - import dmrlink_config + from DMRlink.dmrlink_config import build_config + from DMRlink.dmrlink_log import config_logging # Change the current directory to the location of the application os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) @@ -644,60 +643,36 @@ if __name__ == '__main__': cli_args.CFG_FILE = os.path.dirname(os.path.abspath(__file__))+'/dmrlink.cfg' # Call the external routine to build the configuration dictionary - CONFIG = dmrlink_config.build_config(cli_args.CFG_FILE) + CONFIG = build_config(cli_args.CFG_FILE) # Call the external routing to start the system logger if cli_args.LOG_LEVEL: CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL if cli_args.LOG_HANDLERS: CONFIG['LOGGER']['LOG_HANDLERS'] = cli_args.LOG_HANDLERS - logger = dmrlink_log.config_logging(CONFIG['LOGGER']) - - logger.info('DMRlink \'ambe_audio.py\' (c) 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') + logger = config_logging(CONFIG['LOGGER']) + logger.info('DMRlink \'dmrlink.py\' (c) 2013 - 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') - # ID ALIAS CREATION - # Download - 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']) - logger.info(result) - # Try updating subscriber aliases file - result = try_download(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['SUBSCRIBER_FILE'], CONFIG['ALIASES']['SUBSCRIBER_URL'], CONFIG['ALIASES']['STALE_TIME']) - logger.info(result) - - # Make Dictionaries - peer_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['PEER_FILE']) - if peer_ids: - logger.info('ID ALIAS MAPPER: peer_ids dictionary is available') - - subscriber_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['SUBSCRIBER_FILE']) - if subscriber_ids: - logger.info('ID ALIAS MAPPER: subscriber_ids dictionary is available') - - talkgroup_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['TGID_FILE']) - if talkgroup_ids: - logger.info('ID ALIAS MAPPER: talkgroup_ids dictionary is available') - - # Shut ourselves down gracefully with the IPSC peers. + # Set signal handers so that we can gracefully exit if need be def sig_handler(_signal, _frame): logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) - for system in systems: - this_ipsc = systems[system] - logger.info('De-Registering from IPSC %s', system) - de_reg_req_pkt = this_ipsc.hashed_packet(this_ipsc._local['AUTH_KEY'], this_ipsc.DE_REG_REQ_PKT) - this_ipsc.send_to_ipsc(de_reg_req_pkt) + systems[system].de_register_self() reactor.stop() - - # Set signal handers so that we can gracefully exit if need be + for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]: signal.signal(sig, sig_handler) + # INITIALIZE THE REPORTING LOOP + report_server = config_reports(CONFIG, logger, reportFactory) - # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGUED IPSC - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['LOCAL']['ENABLED']: - systems[system] = ambeIPSC(system, CONFIG, logger) - reactor.listenUDP(CONFIG['SYSTEMS'][system]['LOCAL']['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['LOCAL']['IP']) - - reactor.run() + # Build ID Aliases + peer_ids, subscriber_ids, talkgroup_ids, local_ids = build_aliases(CONFIG, logger) + + # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGRUED IPSC + systems = mk_ipsc_systems(CONFIG, logger, systems, ambeIPSC, report_server) + + + + # INITIALIZATION COMPLETE -- START THE REACTOR + reactor.run() \ No newline at end of file diff --git a/bridge.py b/bridge.py index c7431ca..afdf2c5 100755 --- a/bridge.py +++ b/bridge.py @@ -54,8 +54,8 @@ import sys from dmr_utils.utils import hex_str_3, hex_str_4, int_id -from dmrlink import IPSC, systems, config_reports -from ipsc.ipsc_const import BURST_DATA_TYPE +from dmrlink import IPSC, mk_ipsc_systems, systems, reportFactory, REPORT_OPCODES, build_aliases, config_reports +from DMRlink.ipsc_const import BURST_DATA_TYPE __author__ = 'Cortney T. Buffington, N0MJS' @@ -70,6 +70,7 @@ __email__ = 'n0mjs@me.com' # TS_CLEAR_TIME = .2 + # Import Bridging rules # Note: A stanza *must* exist for any IPSC configured in the main # configuration file and listed as "active". It can be empty, @@ -158,7 +159,7 @@ def build_acl(_sub_acl): return ACL - + # Run this every minute for rule timer updates def rule_timer_loop(): logger.debug('(ALL IPSC) Rule timer loop started') @@ -186,9 +187,9 @@ def rule_timer_loop(): class bridgeIPSC(IPSC): - def __init__(self, _name, _config, _logger, _bridges): - IPSC.__init__(self, _name, _config, _logger) - self.BRIDGES = _bridges + def __init__(self, _name, _config, _logger, report): + IPSC.__init__(self, _name, _config, _logger, report) + self.BRIDGES = BRIDGES if self.BRIDGES: self._logger.info('(%s) Initializing backup/polite bridging', self._system) self.BRIDGE = False @@ -438,15 +439,14 @@ class bridgeIPSC(IPSC): # Send the packet to all peers in the target IPSC systems[target].send_to_ipsc(_tmp_data) - -if __name__ == '__main__': +if __name__ == '__main__': import argparse + import sys import os import signal - from dmr_utils.utils import try_download, mk_id_dict - import dmrlink_log - import dmrlink_config + from DMRlink.dmrlink_config import build_config + from DMRlink.dmrlink_log import config_logging # Change the current directory to the location of the application os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) @@ -460,39 +460,32 @@ if __name__ == '__main__': if not cli_args.CFG_FILE: cli_args.CFG_FILE = os.path.dirname(os.path.abspath(__file__))+'/dmrlink.cfg' - + # Call the external routine to build the configuration dictionary - CONFIG = dmrlink_config.build_config(cli_args.CFG_FILE) - + CONFIG = build_config(cli_args.CFG_FILE) + # Call the external routing to start the system logger if cli_args.LOG_LEVEL: CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL if cli_args.LOG_HANDLERS: CONFIG['LOGGER']['LOG_HANDLERS'] = cli_args.LOG_HANDLERS - logger = dmrlink_log.config_logging(CONFIG['LOGGER']) - - # Call the external routing to start the system logger - logger = dmrlink_log.config_logging(CONFIG['LOGGER']) + logger = config_logging(CONFIG['LOGGER']) + logger.info('DMRlink \'dmrlink.py\' (c) 2013 - 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') - config_reports(CONFIG) - - logger.info('DMRlink \'bridge.py\' (c) 2013-2015 N0MJS & the K0USY Group - SYSTEM STARTING...') - - # Shut ourselves down gracefully with the IPSC peers. + # Set signal handers so that we can gracefully exit if need be def sig_handler(_signal, _frame): logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) - for system in systems: - this_ipsc = systems[system] - logger.info('De-Registering from IPSC %s', system) - de_reg_req_pkt = this_ipsc.hashed_packet(this_ipsc._local['AUTH_KEY'], this_ipsc.DE_REG_REQ_PKT) - this_ipsc.send_to_ipsc(de_reg_req_pkt) + systems[system].de_register_self() reactor.stop() - - # Set signal handers so that we can gracefully exit if need be + for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]: signal.signal(sig, sig_handler) + + + # BRIDGE.PY SPECIFIC ITEMS GO HERE: + # Build the routing rules file RULES = build_rules('bridge_rules') @@ -501,22 +494,25 @@ if __name__ == '__main__': # Build the Access Control List ACL = build_acl('sub_acl') - - - # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGUED IPSC - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['LOCAL']['ENABLED']: - systems[system] = bridgeIPSC(system, CONFIG, logger, BRIDGES) - reactor.listenUDP(CONFIG['SYSTEMS'][system]['LOCAL']['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['LOCAL']['IP']) - - # INITIALIZE THE REPORTING LOOP IF CONFIGURED - if CONFIG['REPORTS']['REPORT_NETWORKS']: - reporting_loop = config_reports(CONFIG) - reporting = task.LoopingCall(reporting_loop, logger) - reporting.start(CONFIG['REPORTS']['REPORT_INTERVAL']) # INITIALIZE THE REPORTING LOOP IF CONFIGURED rule_timer = task.LoopingCall(rule_timer_loop) rule_timer.start(60) + + + + # MAIN INITIALIZATION ITEMS HERE + + # INITIALIZE THE REPORTING LOOP + report_server = config_reports(CONFIG, logger, reportFactory) + + # Build ID Aliases + peer_ids, subscriber_ids, talkgroup_ids, local_ids = build_aliases(CONFIG, logger) + + # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGURED IPSC + systems = mk_ipsc_systems(CONFIG, logger, systems, bridgeIPSC, report_server) + + + # INITIALIZATION COMPLETE -- START THE REACTOR reactor.run() diff --git a/confbridge.py b/confbridge.py index 67acf90..3f84fec 100755 --- a/confbridge.py +++ b/confbridge.py @@ -44,20 +44,21 @@ # Use to make test strings: #print('PKT:', "\\x".join("{:02x}".format(ord(c)) for c in _data)) from __future__ import print_function + from twisted.internet.protocol import Factory, Protocol from twisted.protocols.basic import NetstringReceiver from twisted.internet import reactor from twisted.internet import task + from binascii import b2a_hex as ahex from time import time from importlib import import_module -import cPickle as pickle -import sys +import cPickle as pickle from dmr_utils.utils import hex_str_3, hex_str_4, int_id -from dmrlink import IPSC, systems, config_reports, reportFactory, REPORT_OPCODES # hmac_new, sha1, report +from dmrlink import IPSC, mk_ipsc_systems, systems, reportFactory, REPORT_OPCODES, build_aliases from DMRlink.ipsc_const import BURST_DATA_TYPE @@ -73,6 +74,47 @@ __email__ = 'n0mjs@me.com' # TS_CLEAR_TIME = .2 +# Declare this here so that we can define functions around it +# +BRIDGES = {} + +# Timed loop used for reporting IPSC status +# +# REPORT BASED ON THE TYPE SELECTED IN THE MAIN CONFIG FILE +def config_reports(_config, _logger, _factory): + if _config['REPORTS']['REPORT_NETWORKS'] == 'PRINT': + def reporting_loop(_logger): + _logger.debug('Periodic Reporting Loop Started (PRINT)') + for system in _config['SYSTEMS']: + print_master(_config, system) + print_peer_list(_config, system) + + reporting = task.LoopingCall(reporting_loop, _logger) + reporting.start(_config['REPORTS']['REPORT_INTERVAL']) + report_server = False + + elif _config['REPORTS']['REPORT_NETWORKS'] == 'NETWORK': + def reporting_loop(_logger, _server): + _logger.debug('Periodic Reporting Loop Started (NETWORK)') + _server.send_config() + _server.send_bridge() + + _logger.info('DMRlink TCP reporting server starting') + + report_server = _factory(_config, _logger) + report_server.clients = [] + reactor.listenTCP(_config['REPORTS']['REPORT_PORT'], report_server) + + reporting = task.LoopingCall(reporting_loop, _logger, report_server) + reporting.start(_config['REPORTS']['REPORT_INTERVAL']) + + else: + def reporting_loop(_logger): + _logger.debug('Periodic Reporting Loop Started (NULL)') + report_server = False + + return report_server + # Build the conference bridging structure from the bridge file. # def make_bridge_config(_confbridge_rules): @@ -138,39 +180,7 @@ def build_acl(_sub_acl): return True return ACL - -# Timed loop used for reporting IPSC status -# -# REPORT BASED ON THE TYPE SELECTED IN THE MAIN CONFIG FILE -def config_reports(_config): - if _config['REPORTS']['REPORT_NETWORKS'] == 'PICKLE': - def reporting_loop(_logger): - _logger.debug('Periodic Reporting Loop Started (PICKLE)') - try: - with open(_config['REPORTS']['REPORT_PATH']+'dmrlink_stats.pickle', 'wb') as file: - pickle.dump(_config['SYSTEMS'], file, 2) - file.close() - except IOError as detail: - _logger.error('I/O Error: %s', detail) - - elif _config['REPORTS']['REPORT_NETWORKS'] == 'PRINT': - def reporting_loop(_logger): - _logger.debug('Periodic Reporting Loop Started (PRINT)') - for system in _config['SYSTEMS']: - print_master(_config, system) - print_peer_list(_config, system) - - elif _config['REPORTS']['REPORT_NETWORKS'] == 'NETWORK': - def reporting_loop(_logger, _server): - _logger.debug('Periodic Reporting Loop Started (NETWORK)') - _server.send_config() - _server.send_bridge(BRIDGES) - else: - def reporting_loop(_logger): - _logger.debug('Periodic Reporting Loop Started (NULL)') - - return reporting_loop # Run this every minute for rule timer updates def rule_timer_loop(): @@ -407,25 +417,25 @@ class confbridgeIPSC(IPSC): # END IN-BAND SIGNALLING # -class confReportFactory(reportFactory): +class confbridgeReportFactory(reportFactory): - def send_bridge(self, _bridges): - serialized = pickle.dumps(_bridges, protocol=pickle.HIGHEST_PROTOCOL) + def send_bridge(self): + serialized = pickle.dumps(BRIDGES, protocol=pickle.HIGHEST_PROTOCOL) self.send_clients(REPORT_OPCODES['BRIDGE_SND']+serialized) def send_bridgeEvent(self, _data): self.send_clients(REPORT_OPCODES['BRDG_EVENT']+_data) - - + + if __name__ == '__main__': import argparse + import sys import os import signal - from dmr_utils.utils import try_download, mk_id_dict - + from DMRlink.dmrlink_config import build_config from DMRlink.dmrlink_log import config_logging - + # Change the current directory to the location of the application os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) @@ -438,59 +448,40 @@ if __name__ == '__main__': if not cli_args.CFG_FILE: cli_args.CFG_FILE = os.path.dirname(os.path.abspath(__file__))+'/dmrlink.cfg' - + # Call the external routine to build the configuration dictionary CONFIG = build_config(cli_args.CFG_FILE) - + # Call the external routing to start the system logger if cli_args.LOG_LEVEL: CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL if cli_args.LOG_HANDLERS: CONFIG['LOGGER']['LOG_HANDLERS'] = cli_args.LOG_HANDLERS logger = config_logging(CONFIG['LOGGER']) - - config_reports(CONFIG) - - logger.info('DMRlink \'confbridge.py\' (c) 2016 N0MJS & the K0USY Group - SYSTEM STARTING...') - - - # Shut ourselves down gracefully with the IPSC peers. - def sig_handler(_signal, _frame): - logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) - - for system in systems: - this_ipsc = systems[system] - logger.info('De-Registering from IPSC %s', system) - de_reg_req_pkt = this_ipsc.hashed_packet(this_ipsc._local['AUTH_KEY'], this_ipsc.DE_REG_REQ_PKT) - this_ipsc.send_to_ipsc(de_reg_req_pkt) - reactor.stop() + logger.info('DMRlink \'dmrlink.py\' (c) 2013 - 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') # Set signal handers so that we can gracefully exit if need be + def sig_handler(_signal, _frame): + logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) + for system in systems: + systems[system].de_register_self() + reactor.stop() + for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]: signal.signal(sig, sig_handler) - # ID ALIAS CREATION - # Download - 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']) - logger.info(result) - # Try updating subscriber aliases file - result = try_download(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['SUBSCRIBER_FILE'], CONFIG['ALIASES']['SUBSCRIBER_URL'], CONFIG['ALIASES']['STALE_TIME']) - logger.info(result) - - # Make Dictionaries - peer_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['PEER_FILE']) - if peer_ids: - logger.info('ID ALIAS MAPPER: peer_ids dictionary is available') - - subscriber_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['SUBSCRIBER_FILE']) - if subscriber_ids: - logger.info('ID ALIAS MAPPER: subscriber_ids dictionary is available') + # INITIALIZE THE REPORTING LOOP + report_server = config_reports(CONFIG, logger, confbridgeReportFactory) - talkgroup_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['TGID_FILE']) - if talkgroup_ids: - logger.info('ID ALIAS MAPPER: talkgroup_ids dictionary is available') + # Build ID Aliases + peer_ids, subscriber_ids, talkgroup_ids, local_ids = build_aliases(CONFIG, logger) + + # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGURED IPSC + systems = mk_ipsc_systems(CONFIG, logger, systems, confbridgeIPSC, report_server) + + + + # CONFBRIDGE.PY SPECIFIC ITEMS GO HERE: # Build the routing rules and other configuration CONFIG_DICT = make_bridge_config('confbridge_rules') @@ -499,33 +490,10 @@ if __name__ == '__main__': # Build the Access Control List ACL = build_acl('sub_acl') - - # INITIALIZE THE REPORTING LOOP IF CONFIGURED - if CONFIG['REPORTS']['REPORT_NETWORKS'] == 'PRINT' or CONFIG['REPORTS']['REPORT_NETWORKS'] == 'PICKLE': - reporting_loop = config_reports(CONFIG) - reporting = task.LoopingCall(reporting_loop, logger) - reporting.start(CONFIG['REPORTS']['REPORT_INTERVAL']) - - # INITIALIZE THE NETWORK-BASED REPORTING SERVER - if CONFIG['REPORTS']['REPORT_NETWORKS'] == 'NETWORK': - logger.info('(confbridge.py) TCP reporting server starting') - - report_server = confReportFactory(CONFIG, logger) - report_server.clients = [] - reactor.listenTCP(CONFIG['REPORTS']['REPORT_PORT'], report_server) - - reporting_loop = config_reports(CONFIG) - reporting = task.LoopingCall(reporting_loop, logger, report_server) - reporting.start(CONFIG['REPORTS']['REPORT_INTERVAL']) - - # INITIALIZE THE REPORTING LOOP IF CONFIGURED - rule_timer = task.LoopingCall(rule_timer_loop) - rule_timer.start(60) - - # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGUED IPSC - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['LOCAL']['ENABLED']: - systems[system] = confbridgeIPSC(system, CONFIG, logger, report_server) - reactor.listenUDP(CONFIG['SYSTEMS'][system]['LOCAL']['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['LOCAL']['IP']) + # Initialize the rule timer loop + rule_timer = task.LoopingCall(rule_timer_loop) + rule_timer.start(60) + + # INITIALIZATION COMPLETE -- START THE REACTOR reactor.run() diff --git a/dmrlink.py b/dmrlink.py index 8674101..35122a7 100755 --- a/dmrlink.py +++ b/dmrlink.py @@ -49,7 +49,7 @@ from DMRlink.ipsc_mask import * from DMRlink.reporting_const import * # Imports from DMR Utilities package -from dmr_utils.utils import hex_str_2, hex_str_3, hex_str_4, int_id +from dmr_utils.utils import hex_str_2, hex_str_3, hex_str_4, int_id, try_download, mk_id_dict __author__ = 'Cortney T. Buffington, N0MJS' @@ -67,24 +67,79 @@ systems = {} # Timed loop used for reporting IPSC status # # REPORT BASED ON THE TYPE SELECTED IN THE MAIN CONFIG FILE -def config_reports(_config): +def config_reports(_config, _logger, _factory): if _config['REPORTS']['REPORT_NETWORKS'] == 'PRINT': def reporting_loop(_logger): _logger.debug('Periodic Reporting Loop Started (PRINT)') for system in _config['SYSTEMS']: print_master(_config, system) print_peer_list(_config, system) + + reporting = task.LoopingCall(reporting_loop, _logger) + reporting.start(_config['REPORTS']['REPORT_INTERVAL']) + report_server = False elif _config['REPORTS']['REPORT_NETWORKS'] == 'NETWORK': def reporting_loop(_logger, _server): _logger.debug('Periodic Reporting Loop Started (NETWORK)') _server.send_config() + + _logger.info('DMRlink TCP reporting server starting') + + report_server = _factory(_config, _logger) + report_server.clients = [] + reactor.listenTCP(_config['REPORTS']['REPORT_PORT'], report_server) + + reporting = task.LoopingCall(reporting_loop, _logger, report_server) + reporting.start(_config['REPORTS']['REPORT_INTERVAL']) else: def reporting_loop(_logger): _logger.debug('Periodic Reporting Loop Started (NULL)') + report_server = False - return reporting_loop + return report_server + + +# ID ALIAS CREATION +# Download +def build_aliases(_config, _logger): + 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']) + _logger.info(result) + # Try updating subscriber aliases file + result = try_download(_config['ALIASES']['PATH'], _config['ALIASES']['SUBSCRIBER_FILE'], _config['ALIASES']['SUBSCRIBER_URL'], _config['ALIASES']['STALE_TIME']) + _logger.info(result) + + # Make Dictionaries + peer_ids = mk_id_dict(_config['ALIASES']['PATH'], _config['ALIASES']['PEER_FILE']) + if peer_ids: + _logger.info('ID ALIAS MAPPER: peer_ids dictionary is available') + + subscriber_ids = mk_id_dict(_config['ALIASES']['PATH'], _config['ALIASES']['SUBSCRIBER_FILE']) + if subscriber_ids: + _logger.info('ID ALIAS MAPPER: subscriber_ids dictionary is available') + + talkgroup_ids = mk_id_dict(_config['ALIASES']['PATH'], _config['ALIASES']['TGID_FILE']) + if talkgroup_ids: + _logger.info('ID ALIAS MAPPER: talkgroup_ids dictionary is available') + + local_ids = mk_id_dict(_config['ALIASES']['PATH'], _config['ALIASES']['LOCAL_FILE']) + if local_ids: + _logger.info('ID ALIAS MAPPER: local_ids dictionary is available') + + return(peer_ids, subscriber_ids, talkgroup_ids, local_ids) + + +# Make the IPSC systems from the config and the class used to build them. +# +def mk_ipsc_systems(_config, _logger, _systems, _ipsc, _report_server): + for system in _config['SYSTEMS']: + if _config['SYSTEMS'][system]['LOCAL']['ENABLED']: + _systems[system] = _ipsc(system, _config, _logger, _report_server) + reactor.listenUDP(_config['SYSTEMS'][system]['LOCAL']['PORT'], _systems[system], interface=_config['SYSTEMS'][system]['LOCAL']['IP']) + return _systems # Process the MODE byte in registration/peer list packets for determining master and peer capabilities # @@ -310,7 +365,13 @@ class IPSC(DatagramProtocol): else: self._logger.warning('(%s) Peer De-Registration Requested for: %s, but we don\'t have a listing for this peer', self._system, int_id(_peerid)) pass - + + # De-register ourselves from the IPSC + def de_register_self(self): + self._logger.info('(%s) De-Registering self from the IPSC system', self._system) + de_reg_req_pkt = self.hashed_packet(self._local['AUTH_KEY'], self.DE_REG_REQ_PKT) + self.send_to_ipsc(de_reg_req_pkt) + # Take a received peer list and the network it belongs to, process and populate the # data structure in my_ipsc_config with the results, and return a simple list of peers. # @@ -977,10 +1038,6 @@ class reportFactory(Factory): serialized = pickle.dumps(self._config['SYSTEMS'], protocol=pickle.HIGHEST_PROTOCOL) self.send_clients(REPORT_OPCODES['CONFIG_SND']+serialized) - def send_bridge(self, ): - serialized = pickle.dumps(self._config['SYSTEMS'], protocol=pickle.HIGHEST_PROTOCOL) - self.send_clients(REPORT_OPCODES['CONFIG_SND']+serialized) - def send_rcm(self, _data): self.send_clients(REPORT_OPCODES['RCM_SND']+_data) @@ -1011,7 +1068,6 @@ if __name__ == '__main__': if not cli_args.CFG_FILE: cli_args.CFG_FILE = os.path.dirname(os.path.abspath(__file__))+'/dmrlink.cfg' - # Call the external routine to build the configuration dictionary CONFIG = build_config(cli_args.CFG_FILE) @@ -1023,47 +1079,26 @@ if __name__ == '__main__': logger = config_logging(CONFIG['LOGGER']) logger.info('DMRlink \'dmrlink.py\' (c) 2013 - 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') - # Set signal handers so that we can gracefully exit if need be def sig_handler(_signal, _frame): logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) - for system in systems: - this_ipsc = systems[system] - logger.info('De-Registering from IPSC %s', system) - de_reg_req_pkt = this_ipsc.hashed_packet(this_ipsc._local['AUTH_KEY'], this_ipsc.DE_REG_REQ_PKT) - this_ipsc.send_to_ipsc(de_reg_req_pkt) + systems[system].de_register_self() reactor.stop() for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]: signal.signal(sig, sig_handler) # INITIALIZE THE REPORTING LOOP - config_reports(CONFIG) + report_server = config_reports(CONFIG, logger, reportFactory) - if CONFIG['REPORTS']['REPORT_NETWORKS'] == 'PRINT': - reporting_loop = config_reports(CONFIG) - reporting = task.LoopingCall(reporting_loop, logger) - reporting.start(CONFIG['REPORTS']['REPORT_INTERVAL']) - report_server = False + # Build ID Aliases + peer_ids, subscriber_ids, talkgroup_ids, local_ids = build_aliases(CONFIG, logger) - elif CONFIG['REPORTS']['REPORT_NETWORKS'] == 'NETWORK': - logger.info('(confbridge.py) TCP reporting server starting') - - report_server = reportFactory(CONFIG, logger) - report_server.clients = [] - reactor.listenTCP(CONFIG['REPORTS']['REPORT_PORT'], report_server) - - reporting_loop = config_reports(CONFIG) - reporting = task.LoopingCall(reporting_loop, logger, report_server) - reporting.start(CONFIG['REPORTS']['REPORT_INTERVAL']) - - # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGUED IPSC - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['LOCAL']['ENABLED']: - systems[system] = IPSC(system, CONFIG, logger, report_server) - reactor.listenUDP(CONFIG['SYSTEMS'][system]['LOCAL']['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['LOCAL']['IP']) - + # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGRUED IPSC + systems = mk_ipsc_systems(CONFIG, logger, systems, IPSC, report_server) - + + + # INITIALIZATION COMPLETE -- START THE REACTOR reactor.run() diff --git a/dmrlink/dmrlink_config.py b/dmrlink/dmrlink_config.py index 580d3e9..812c119 100755 --- a/dmrlink/dmrlink_config.py +++ b/dmrlink/dmrlink_config.py @@ -56,7 +56,6 @@ def build_config(_config_file): 'REPORT_NETWORKS': config.get(section, 'REPORT_NETWORKS'), 'REPORT_RCM': config.get(section, 'REPORT_RCM'), 'REPORT_INTERVAL': config.getint(section, 'REPORT_INTERVAL'), - 'REPORT_PATH': config.get(section, 'REPORT_PATH'), 'REPORT_PORT': config.get(section, 'REPORT_PORT'), 'REPORT_CLIENTS': config.get(section, 'REPORT_CLIENTS').split(','), 'PRINT_PEERS_INC_MODE': config.getboolean(section, 'PRINT_PEERS_INC_MODE'), @@ -82,6 +81,7 @@ def build_config(_config_file): 'PEER_FILE': config.get(section, 'PEER_FILE'), 'SUBSCRIBER_FILE': config.get(section, 'SUBSCRIBER_FILE'), 'TGID_FILE': config.get(section, 'TGID_FILE'), + 'LOCAL_FILE': config.get(section, 'LOCAL_FILE'), 'PEER_URL': config.get(section, 'PEER_URL'), 'SUBSCRIBER_URL': config.get(section, 'SUBSCRIBER_URL'), 'STALE_TIME': config.getint(section, 'STALE_DAYS') * 86400, diff --git a/dmrlink_SAMPLE.cfg b/dmrlink_SAMPLE.cfg index 456b80f..321fef5 100644 --- a/dmrlink_SAMPLE.cfg +++ b/dmrlink_SAMPLE.cfg @@ -16,9 +16,8 @@ PATH: /opt/dmrlink/ # NETWORK REPORTING CONFIGURATION # Enabling "REPORT_NETWORKS" will cause a reporting action for # IPSC each time the periodic reporting loop runs, that period is -# specifiec by "REPORT_INTERVAL" in seconds. Possible values +# specified by "REPORT_INTERVAL" in seconds. Possible values # for "REPORT_NETWORKS" are: -# PICKLE - a Python pickle file of the network's data structure # # PRINT - a pretty print (STDOUT) of the data structure # "PRINT_PEERS_INC_MODE" - Boolean to include mode bits @@ -31,16 +30,15 @@ PATH: /opt/dmrlink/ # goal here is a web dashboard that doesn't live on the # dmrlink machine itself. # -# PRINT is the odd man out because it sends prettily formatted stuff -# to STDOUT. The others send the internal data structure of the IPSC -# instance and let some program on the other end sort it out. +# PRINT should only be used for debugging; it sends prettily formatted +# stuff to STDOUT. The others send the internal data structure of the +# IPSC instance and let some program on the other end sort it out. # # REPORT_RCM - If True, and REPORT_NETWORKS = 'NETWORK', will send RCM # Packets to connected reporting clients. This also requires # individual IPSC systems to have RCM and CON_APP both set 'True' # # REPORT_INTERVAL - Seconds between reports -# REPORT_PATH - Absolute path save data (pickle and json) # REPORT_PORT - TCP port to listen on if "REPORT_NETWORKS" = NETWORK # REPORT_CLIENTS - comma separated list of IPs you will allow clients # to connect on. @@ -49,7 +47,6 @@ PATH: /opt/dmrlink/ REPORT_NETWORKS: REPORT_RCM: REPORT_INTERVAL: 60 -REPORT_PATH: REPORT_PORT: 4321 REPORT_CLIENTS: 127.0.0.1, 192.168.1.1 PRINT_PEERS_INC_MODE: 0 @@ -102,13 +99,13 @@ STALE_DAYS: 7 # # [NAME] The name you want to use to identify the IPSC instance (use # something better than "IPSC1"...) -# ENABLED: Should we communiate with this network? Handy if you need to +# ENABLED: Should we communicate with this network? Handy if you need to # shut one down but don't want to lose the config # RADIO_ID: This is the radio ID that DMRLink should use to communicate # IP: This is the local IPv4 address to listen on. It may be left # blank if you do not need or wish to specify. It is mostly # useful when DMRlink uses multiple interfaces to serve as an -# application gatway/proxy from private and/or VPN networks +# application gateway/proxy from private and/or VPN networks # to the real world. # PORT: This is the UDP source port for DMRLink to use for this # PSC network, must be unique!!! @@ -122,7 +119,7 @@ STALE_DAYS: 7 # CSBK_CALL: Should be False, we cannot process these, but may be useful # for debugging. # RCM: Repeater Call Monitoring - don't unable unless you plan to -# actually use it, this craetes extra network traffic. +# actually use it, this creates extra network traffic. # CON_APP: Third Party Console App - exactly what DMRlink is, should # be set to True, and must be if you intend to process RCM # packets (like with network-based reporting) @@ -135,7 +132,7 @@ STALE_DAYS: 7 # AUTH_ENABLED: Do we use authenticated IPSC? # AUTH_KEY: The Authentication key (up to 40 hex characters) # MASTER_IP: IP address of the IPSC master (ignored if DMRlink is the master) -# MASTER_PORT: UDP port of the IPSC master (ignored if DMRlinkn is the master) +# MASTER_PORT: UDP port of the IPSC master (ignored if DMRlink is the master) # GROUP_HANGTIME: Group hangtime, per DMR configuration # # ...Repeat the block for each IPSC network to join. diff --git a/log.py b/log.py index 6c6931c..9f8ca5e 100755 --- a/log.py +++ b/log.py @@ -25,7 +25,9 @@ from twisted.internet import reactor from binascii import b2a_hex as h import time -from dmrlink import IPSC, systems + +from dmrlink import IPSC, mk_ipsc_systems, systems, reportFactory, build_aliases, config_reports + from dmr_utils.utils import hex_str_3, hex_str_4, int_id, get_alias __author__ = 'Cortney T. Buffington, N0MJS' @@ -37,8 +39,8 @@ __email__ = 'n0mjs@me.com' class logIPSC(IPSC): - def __init__(self, _name, _config, _logger): - IPSC.__init__(self, _name, _config, _logger) + def __init__(self, _name, _config, _logger, _report): + IPSC.__init__(self, _name, _config, _logger, _report) self.ACTIVE_CALLS = [] #************************************************ @@ -89,13 +91,12 @@ class logIPSC(IPSC): if __name__ == '__main__': import argparse - import os import sys + import os import signal - from dmr_utils.utils import try_download, mk_id_dict - import dmrlink_log - import dmrlink_config + from DMRlink.dmrlink_config import build_config + from DMRlink.dmrlink_log import config_logging # Change the current directory to the location of the application os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) @@ -103,62 +104,44 @@ if __name__ == '__main__': # 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='CFG_FILE', help='/full/path/to/config.file (usually dmrlink.cfg)') + parser.add_argument('-ll', '--log_level', action='store', dest='LOG_LEVEL', help='Override config file logging level.') + parser.add_argument('-lh', '--log_handle', action='store', dest='LOG_HANDLERS', help='Override config file logging handler.') cli_args = parser.parse_args() if not cli_args.CFG_FILE: cli_args.CFG_FILE = os.path.dirname(os.path.abspath(__file__))+'/dmrlink.cfg' # Call the external routine to build the configuration dictionary - CONFIG = dmrlink_config.build_config(cli_args.CFG_FILE) + CONFIG = build_config(cli_args.CFG_FILE) # Call the external routing to start the system logger - logger = dmrlink_log.config_logging(CONFIG['LOGGER']) - - logger.info('DMRlink \'log.py\' (c) 2013, 2014 N0MJS & the K0USY Group - SYSTEM STARTING...') + if cli_args.LOG_LEVEL: + CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL + if cli_args.LOG_HANDLERS: + CONFIG['LOGGER']['LOG_HANDLERS'] = cli_args.LOG_HANDLERS + logger = config_logging(CONFIG['LOGGER']) + logger.info('DMRlink \'dmrlink.py\' (c) 2013 - 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') - # ID ALIAS CREATION - # Download - 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']) - logger.info(result) - # Try updating subscriber aliases file - result = try_download(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['SUBSCRIBER_FILE'], CONFIG['ALIASES']['SUBSCRIBER_URL'], CONFIG['ALIASES']['STALE_TIME']) - logger.info(result) - - # Make Dictionaries - peer_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['PEER_FILE']) - if peer_ids: - logger.info('ID ALIAS MAPPER: peer_ids dictionary is available') - - subscriber_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['SUBSCRIBER_FILE']) - if subscriber_ids: - logger.info('ID ALIAS MAPPER: subscriber_ids dictionary is available') - - talkgroup_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['TGID_FILE']) - if talkgroup_ids: - logger.info('ID ALIAS MAPPER: talkgroup_ids dictionary is available') - - # Shut ourselves down gracefully with the IPSC peers. + # Set signal handers so that we can gracefully exit if need be def sig_handler(_signal, _frame): logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) - for system in systems: - this_ipsc = systems[system] - logger.info('De-Registering from IPSC %s', system) - de_reg_req_pkt = this_ipsc.hashed_packet(this_ipsc._local['AUTH_KEY'], this_ipsc.DE_REG_REQ_PKT) - this_ipsc.send_to_ipsc(de_reg_req_pkt) + systems[system].de_register_self() reactor.stop() - - # Set signal handers so that we can gracefully exit if need be + for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]: signal.signal(sig, sig_handler) + # INITIALIZE THE REPORTING LOOP + report_server = config_reports(CONFIG, logger, reportFactory) - # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGUED IPSC - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['LOCAL']['ENABLED']: - systems[system] = logIPSC(system, CONFIG, logger) - reactor.listenUDP(CONFIG['SYSTEMS'][system]['LOCAL']['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['LOCAL']['IP']) - + # Build ID Aliases + peer_ids, subscriber_ids, talkgroup_ids, local_ids = build_aliases(CONFIG, logger) + + # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGRUED IPSC + systems = mk_ipsc_systems(CONFIG, logger, systems, logIPSC, report_server) + + + + # INITIALIZATION COMPLETE -- START THE REACTOR reactor.run() \ No newline at end of file diff --git a/play_group.py b/play_group.py index 22cd335..1408966 100755 --- a/play_group.py +++ b/play_group.py @@ -36,10 +36,10 @@ from twisted.internet import reactor import sys, time import cPickle as pickle -from dmrlink import IPSC, systems +from dmrlink import IPSC, mk_ipsc_systems, systems, reportFactory, build_aliases, config_reports from dmr_utils.utils import int_id, hex_str_3 -from ipsc.ipsc_const import BURST_DATA_TYPE +from DMRlink.ipsc_const import BURST_DATA_TYPE __author__ = 'Cortney T. Buffington, N0MJS' __copyright__ = 'Copyright (c) 2014 - 2015 Cortney T. Buffington, N0MJS and the K0USY Group' @@ -61,8 +61,8 @@ trigger_groups_1 = ['\x00\x00\x01', '\x00\x00\x0D', '\x00\x00\x64'] trigger_groups_2 = ['\x00\x0C\x30',] class playIPSC(IPSC): - def __init__(self, _name, _config, _logger): - IPSC.__init__(self, _name, _config, _logger) + def __init__(self, _name, _config, _logger,_report): + IPSC.__init__(self, _name, _config, _logger, _report) self.CALL_DATA = [] self.event_id = 1 @@ -134,12 +134,12 @@ class playIPSC(IPSC): if __name__ == '__main__': import argparse - import os import sys + import os import signal - import dmrlink_log - import dmrlink_config + from DMRlink.dmrlink_config import build_config + from DMRlink.dmrlink_log import config_logging # Change the current directory to the location of the application os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) @@ -153,39 +153,38 @@ if __name__ == '__main__': if not cli_args.CFG_FILE: cli_args.CFG_FILE = os.path.dirname(os.path.abspath(__file__))+'/dmrlink.cfg' - + # Call the external routine to build the configuration dictionary - CONFIG = dmrlink_config.build_config(cli_args.CFG_FILE) - + CONFIG = build_config(cli_args.CFG_FILE) + # Call the external routing to start the system logger if cli_args.LOG_LEVEL: CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL if cli_args.LOG_HANDLERS: CONFIG['LOGGER']['LOG_HANDLERS'] = cli_args.LOG_HANDLERS - logger = dmrlink_log.config_logging(CONFIG['LOGGER']) - - logger.info('DMRlink \'record.py\' (c) 2014 N0MJS & the K0USY Group - SYSTEM STARTING...') + logger = config_logging(CONFIG['LOGGER']) + logger.info('DMRlink \'dmrlink.py\' (c) 2013 - 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') - # Shut ourselves down gracefully with the IPSC peers. + # Set signal handers so that we can gracefully exit if need be def sig_handler(_signal, _frame): logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) - for system in systems: - this_ipsc = systems[system] - logger.info('De-Registering from IPSC %s', system) - de_reg_req_pkt = this_ipsc.hashed_packet(this_ipsc._local['AUTH_KEY'], this_ipsc.DE_REG_REQ_PKT) - this_ipsc.send_to_ipsc(de_reg_req_pkt) + systems[system].de_register_self() reactor.stop() - - # Set signal handers so that we can gracefully exit if need be + for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]: signal.signal(sig, sig_handler) + # INITIALIZE THE REPORTING LOOP + report_server = config_reports(CONFIG, logger, reportFactory) - # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGUED IPSC - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['LOCAL']['ENABLED']: - systems[system] = playIPSC(system, CONFIG, logger) - reactor.listenUDP(CONFIG['SYSTEMS'][system]['LOCAL']['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['LOCAL']['IP']) - - reactor.run() + # Build ID Aliases + peer_ids, subscriber_ids, talkgroup_ids, local_ids = build_aliases(CONFIG, logger) + + # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGRUED IPSC + systems = mk_ipsc_systems(CONFIG, logger, systems, playIPSC, report_server) + + + + # INITIALIZATION COMPLETE -- START THE REACTOR + reactor.run() \ No newline at end of file diff --git a/playback.py b/playback.py index 41b2a1b..a2e34cd 100755 --- a/playback.py +++ b/playback.py @@ -25,7 +25,7 @@ from twisted.internet import reactor from binascii import b2a_hex as ahex import sys, time -from dmrlink import IPSC, systems +from dmrlink import IPSC, mk_ipsc_systems, systems, reportFactory, build_aliases, config_reports from dmr_utils.utils import int_id, hex_str_3 __author__ = 'Cortney T. Buffington, N0MJS' @@ -46,8 +46,8 @@ HEX_SUB = hex_str_3(SUB) BOGUS_SUB = '\xFF\xFF\xFF' class playbackIPSC(IPSC): - def __init__(self, _name, _config, _logger): - IPSC.__init__(self, _name, _config, _logger) + def __init__(self, _name, _config, _logger, _report): + IPSC.__init__(self, _name, _config, _logger, _report) self.CALL_DATA = [] if GROUP_SRC_SUB: @@ -115,12 +115,12 @@ class playbackIPSC(IPSC): if __name__ == '__main__': import argparse - import os import sys + import os import signal - import dmrlink_log - import dmrlink_config + from DMRlink.dmrlink_config import build_config + from DMRlink.dmrlink_log import config_logging # Change the current directory to the location of the application os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) @@ -134,39 +134,38 @@ if __name__ == '__main__': if not cli_args.CFG_FILE: cli_args.CFG_FILE = os.path.dirname(os.path.abspath(__file__))+'/dmrlink.cfg' - + # Call the external routine to build the configuration dictionary - CONFIG = dmrlink_config.build_config(cli_args.CFG_FILE) - + CONFIG = build_config(cli_args.CFG_FILE) + # Call the external routing to start the system logger if cli_args.LOG_LEVEL: CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL if cli_args.LOG_HANDLERS: CONFIG['LOGGER']['LOG_HANDLERS'] = cli_args.LOG_HANDLERS - logger = dmrlink_log.config_logging(CONFIG['LOGGER']) - - logger.info('DMRlink \'playback.py\' (c) 2013, 2014 N0MJS & the K0USY Group - SYSTEM STARTING...') + logger = config_logging(CONFIG['LOGGER']) + logger.info('DMRlink \'dmrlink.py\' (c) 2013 - 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') - # Shut ourselves down gracefully with the IPSC peers. + # Set signal handers so that we can gracefully exit if need be def sig_handler(_signal, _frame): logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) - for system in systems: - this_ipsc = systems[system] - logger.info('De-Registering from IPSC %s', system) - de_reg_req_pkt = this_ipsc.hashed_packet(this_ipsc._local['AUTH_KEY'], this_ipsc.DE_REG_REQ_PKT) - this_ipsc.send_to_ipsc(de_reg_req_pkt) + systems[system].de_register_self() reactor.stop() - - # Set signal handers so that we can gracefully exit if need be + for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]: signal.signal(sig, sig_handler) + # INITIALIZE THE REPORTING LOOP + report_server = config_reports(CONFIG, logger, reportFactory) - # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGUED IPSC - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['LOCAL']['ENABLED']: - systems[system] = playbackIPSC(system, CONFIG, logger) - reactor.listenUDP(CONFIG['SYSTEMS'][system]['LOCAL']['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['LOCAL']['IP']) - + # Build ID Aliases + peer_ids, subscriber_ids, talkgroup_ids, local_ids = build_aliases(CONFIG, logger) + + # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGRUED IPSC + systems = mk_ipsc_systems(CONFIG, logger, systems, playbackIPSC, report_server) + + + + # INITIALIZATION COMPLETE -- START THE REACTOR reactor.run() diff --git a/rcm.py b/rcm.py index 866a0f0..0dff995 100755 --- a/rcm.py +++ b/rcm.py @@ -32,8 +32,9 @@ import datetime import binascii import dmrlink import sys -from dmrlink import IPSC, systems +from dmrlink import IPSC, mk_ipsc_systems, systems, reportFactory, build_aliases, config_reports from dmr_utils.utils import get_alias, int_id +from DMRlink.ipsc_const import * __author__ = 'Cortney T. Buffington, N0MJS' __copyright__ = 'Copyright (c) 2013, 2014 Cortney T. Buffington, N0MJS and the K0USY Group' @@ -43,18 +44,13 @@ __maintainer__ = 'Cort Buffington, N0MJS' __email__ = 'n0mjs@me.com' -try: - from ipsc.ipsc_const import * -except ImportError: - sys.exit('IPSC message types file not found or invalid') - status = True rpt = True nack = True class rcmIPSC(IPSC): - def __init__(self, _name, _config, _logger): - IPSC.__init__(self, _name, _config, _logger) + def __init__(self, _name, _config, _logger, _report): + IPSC.__init__(self, _name, _config, _logger, _report) #************************************************ # CALLBACK FUNCTIONS FOR USER PACKET TYPES @@ -149,13 +145,12 @@ class rcmIPSC(IPSC): if __name__ == '__main__': import argparse - import os import sys + import os import signal - from dmr_utils.utils import try_download, mk_id_dict - import dmrlink_log - import dmrlink_config + from DMRlink.dmrlink_config import build_config + from DMRlink.dmrlink_log import config_logging # Change the current directory to the location of the application os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) @@ -169,62 +164,38 @@ if __name__ == '__main__': if not cli_args.CFG_FILE: cli_args.CFG_FILE = os.path.dirname(os.path.abspath(__file__))+'/dmrlink.cfg' - + # Call the external routine to build the configuration dictionary - CONFIG = dmrlink_config.build_config(cli_args.CFG_FILE) - + CONFIG = build_config(cli_args.CFG_FILE) + # Call the external routing to start the system logger if cli_args.LOG_LEVEL: CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL if cli_args.LOG_HANDLERS: CONFIG['LOGGER']['LOG_HANDLERS'] = cli_args.LOG_HANDLERS - logger = dmrlink_log.config_logging(CONFIG['LOGGER']) - - logger.info('DMRlink \'rcm.py\' (c) 2013, 2014 N0MJS & the K0USY Group - SYSTEM STARTING...') + logger = config_logging(CONFIG['LOGGER']) + logger.info('DMRlink \'dmrlink.py\' (c) 2013 - 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') - # ID ALIAS CREATION - # Download - 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']) - logger.info(result) - # Try updating subscriber aliases file - result = try_download(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['SUBSCRIBER_FILE'], CONFIG['ALIASES']['SUBSCRIBER_URL'], CONFIG['ALIASES']['STALE_TIME']) - logger.info(result) - - # Make Dictionaries - peer_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['PEER_FILE']) - if peer_ids: - logger.info('ID ALIAS MAPPER: peer_ids dictionary is available') - - subscriber_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['SUBSCRIBER_FILE']) - if subscriber_ids: - logger.info('ID ALIAS MAPPER: subscriber_ids dictionary is available') - - talkgroup_ids = mk_id_dict(CONFIG['ALIASES']['PATH'], CONFIG['ALIASES']['TGID_FILE']) - if talkgroup_ids: - logger.info('ID ALIAS MAPPER: talkgroup_ids dictionary is available') - - # Shut ourselves down gracefully with the IPSC peers. + # Set signal handers so that we can gracefully exit if need be def sig_handler(_signal, _frame): logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) - for system in systems: - this_ipsc = systems[system] - logger.info('De-Registering from IPSC %s', system) - de_reg_req_pkt = this_ipsc.hashed_packet(this_ipsc._local['AUTH_KEY'], this_ipsc.DE_REG_REQ_PKT) - this_ipsc.send_to_ipsc(de_reg_req_pkt) + systems[system].de_register_self() reactor.stop() - - # Set signal handers so that we can gracefully exit if need be + for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]: signal.signal(sig, sig_handler) + # INITIALIZE THE REPORTING LOOP + report_server = config_reports(CONFIG, logger, reportFactory) - # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGUED IPSC - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['LOCAL']['ENABLED']: - systems[system] = rcmIPSC(system, CONFIG, logger) - reactor.listenUDP(CONFIG['SYSTEMS'][system]['LOCAL']['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['LOCAL']['IP']) - + # Build ID Aliases + peer_ids, subscriber_ids, talkgroup_ids, local_ids = build_aliases(CONFIG, logger) + + # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGRUED IPSC + systems = mk_ipsc_systems(CONFIG, logger, systems, rcmIPSC, report_server) + + + + # INITIALIZATION COMPLETE -- START THE REACTOR reactor.run() diff --git a/rcm_db_log.py b/rcm_db_log.py index 7f5a05f..8ad3273 100755 --- a/rcm_db_log.py +++ b/rcm_db_log.py @@ -44,7 +44,9 @@ from twisted.internet import task import pymysql import dmrlink -from dmrlink import IPSC, NETWORK, networks, get_info, int_id, logger +from dmrlink import IPSC, mk_ipsc_systems, systems, reportFactory, build_aliases, config_reports + +from DMRlink.ipsc_const import * __author__ = 'Cortney T. Buffington, N0MJS' __copyright__ = 'Copyright (c) 2013, 2014 Cortney T. Buffington, N0MJS and the K0USY Group' @@ -70,10 +72,6 @@ db_name = 'dmrlink' # #************************************ -try: - from ipsc.ipsc_message_types import * -except ImportError: - sys.exit('IPSC message types file not found or invalid') class rcmIPSC(IPSC): @@ -110,9 +108,58 @@ class rcmIPSC(IPSC): if __name__ == '__main__': - logger.info('DMRlink \'rcm_db_log.py\' (c) 2013, 2014 N0MJS & the K0USY Group - SYSTEM STARTING...') - for ipsc_network in NETWORK: - if NETWORK[ipsc_network]['LOCAL']['ENABLED']: - networks[ipsc_network] = rcmIPSC(ipsc_network) - reactor.listenUDP(NETWORK[ipsc_network]['LOCAL']['PORT'], networks[ipsc_network], interface=NETWORK[ipsc_network]['LOCAL']['IP']) + import argparse + import sys + import os + import signal + + from DMRlink.dmrlink_config import build_config + from DMRlink.dmrlink_log import config_logging + + # 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='CFG_FILE', help='/full/path/to/config.file (usually dmrlink.cfg)') + parser.add_argument('-ll', '--log_level', action='store', dest='LOG_LEVEL', help='Override config file logging level.') + parser.add_argument('-lh', '--log_handle', action='store', dest='LOG_HANDLERS', help='Override config file logging handler.') + cli_args = parser.parse_args() + + if not cli_args.CFG_FILE: + cli_args.CFG_FILE = os.path.dirname(os.path.abspath(__file__))+'/dmrlink.cfg' + + # Call the external routine to build the configuration dictionary + CONFIG = build_config(cli_args.CFG_FILE) + + # Call the external routing to start the system logger + if cli_args.LOG_LEVEL: + CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL + if cli_args.LOG_HANDLERS: + CONFIG['LOGGER']['LOG_HANDLERS'] = cli_args.LOG_HANDLERS + logger = config_logging(CONFIG['LOGGER']) + logger.info('DMRlink \'dmrlink.py\' (c) 2013 - 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') + + # Set signal handers so that we can gracefully exit if need be + def sig_handler(_signal, _frame): + logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) + for system in systems: + systems[system].de_register_self() + reactor.stop() + + for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]: + signal.signal(sig, sig_handler) + + # INITIALIZE THE REPORTING LOOP + report_server = config_reports(CONFIG, logger, reportFactory) + + # Build ID Aliases + peer_ids, subscriber_ids, talkgroup_ids, local_ids = build_aliases(CONFIG, logger) + + # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGRUED IPSC + systems = mk_ipsc_systems(CONFIG, logger, systems, rcmIPSC, report_server) + + + + # INITIALIZATION COMPLETE -- START THE REACTOR reactor.run() \ No newline at end of file diff --git a/record.py b/record.py index bc5b5aa..d36e23f 100755 --- a/record.py +++ b/record.py @@ -27,7 +27,7 @@ from binascii import b2a_hex as h import sys import cPickle as pickle -from dmrlink import IPSC, systems +from dmrlink import IPSC, mk_ipsc_systems, systems, reportFactory, build_aliases, config_reports from dmr_utils.utils import hex_str_3, int_id __author__ = 'Cortney T. Buffington, N0MJS' @@ -65,8 +65,8 @@ id = hex_str_3(id) filename = raw_input('Filename to use for this recording? ') class recordIPSC(IPSC): - def __init__(self, _name, _config, _logger): - IPSC.__init__(self, _name, _config, _logger) + def __init__(self, _name, _config, _logger, _report): + IPSC.__init__(self, _name, _config, _logger, _report) self.CALL_DATA = [] #************************************************ @@ -106,12 +106,12 @@ class recordIPSC(IPSC): if __name__ == '__main__': import argparse - import os import sys + import os import signal - import dmrlink_log - import dmrlink_config + from DMRlink.dmrlink_config import build_config + from DMRlink.dmrlink_log import config_logging # Change the current directory to the location of the application os.chdir(os.path.dirname(os.path.realpath(sys.argv[0]))) @@ -125,44 +125,38 @@ if __name__ == '__main__': if not cli_args.CFG_FILE: cli_args.CFG_FILE = os.path.dirname(os.path.abspath(__file__))+'/dmrlink.cfg' - + # Call the external routine to build the configuration dictionary - CONFIG = dmrlink_config.build_config(cli_args.CFG_FILE) - + CONFIG = build_config(cli_args.CFG_FILE) + # Call the external routing to start the system logger if cli_args.LOG_LEVEL: CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL if cli_args.LOG_HANDLERS: CONFIG['LOGGER']['LOG_HANDLERS'] = cli_args.LOG_HANDLERS - logger = dmrlink_log.config_logging(CONFIG['LOGGER']) - - CONFIG = dmrlink_config.build_config(cli_args.CFG_FILE) + logger = config_logging(CONFIG['LOGGER']) + logger.info('DMRlink \'dmrlink.py\' (c) 2013 - 2015 N0MJS & the K0USY Group - SYSTEM STARTING...') - # Call the external routing to start the system logger - logger = dmrlink_log.config_logging(CONFIG['LOGGER']) - - logger.info('DMRlink \'record.py\' (c) 2014 N0MJS & the K0USY Group - SYSTEM STARTING...') - - # Shut ourselves down gracefully with the IPSC peers. + # Set signal handers so that we can gracefully exit if need be def sig_handler(_signal, _frame): logger.info('*** DMRLINK IS TERMINATING WITH SIGNAL %s ***', str(_signal)) - for system in systems: - this_ipsc = systems[system] - logger.info('De-Registering from IPSC %s', system) - de_reg_req_pkt = this_ipsc.hashed_packet(this_ipsc._local['AUTH_KEY'], this_ipsc.DE_REG_REQ_PKT) - this_ipsc.send_to_ipsc(de_reg_req_pkt) + systems[system].de_register_self() reactor.stop() - - # Set signal handers so that we can gracefully exit if need be + for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT]: signal.signal(sig, sig_handler) + # INITIALIZE THE REPORTING LOOP + report_server = config_reports(CONFIG, logger, reportFactory) - # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGUED IPSC - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['LOCAL']['ENABLED']: - systems[system] = recordIPSC(system, CONFIG, logger) - reactor.listenUDP(CONFIG['SYSTEMS'][system]['LOCAL']['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['LOCAL']['IP']) - - reactor.run() + # Build ID Aliases + peer_ids, subscriber_ids, talkgroup_ids, local_ids = build_aliases(CONFIG, logger) + + # INITIALIZE AN IPSC OBJECT (SELF SUSTAINING) FOR EACH CONFIGRUED IPSC + systems = mk_ipsc_systems(CONFIG, logger, systems, recordIPSC, report_server) + + + + # INITIALIZATION COMPLETE -- START THE REACTOR + reactor.run() \ No newline at end of file