From 2a4295743ab282ccbb2f40ef62675ec5f5bbea50 Mon Sep 17 00:00:00 2001 From: Cort Buffington Date: Fri, 22 Jun 2018 09:28:31 -0500 Subject: [PATCH] Continued work on socket-based reporting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Status table and bridge table now work. Log messages are sending, but formatting isn’t right yet, so they present as unknown messages. --- hb_confbridge.py | 62 ++++++++++++++++++++++++++++++++++++++++++------ hblink.py | 11 +++++---- sub_acl.py | 2 +- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/hb_confbridge.py b/hb_confbridge.py index f4e717d..6ffccc5 100755 --- a/hb_confbridge.py +++ b/hb_confbridge.py @@ -40,18 +40,21 @@ from time import time from importlib import import_module # Twisted is pretty important, so I keep it separate -from twisted.internet.protocol import DatagramProtocol -from twisted.internet import reactor -from twisted.internet import task +from twisted.internet.protocol import Factory, Protocol +from twisted.protocols.basic import NetstringReceiver +from twisted.internet import reactor, task # Things we import from the main hblink module -from hblink import HBSYSTEM, systems, hblink_handler +from hblink import HBSYSTEM, systems, hblink_handler, reportFactory, REPORT_OPCODES from dmr_utils.utils import hex_str_3, int_id, get_alias from dmr_utils import decode, bptc, const import hb_config import hb_log import hb_const +# Stuff for socket reporting +import cPickle as pickle + # Does anybody read this stuff? There's a PEP somewhere that says I should do this. __author__ = 'Cortney T. Buffington, N0MJS' __copyright__ = 'Copyright (c) 2016 Cortney T. Buffington, N0MJS and the K0USY Group' @@ -63,6 +66,28 @@ __status__ = 'pre-alpha' # Module gobal varaibles + +# Timed loop used for reporting HBP status +# +# REPORT BASED ON THE TYPE SELECTED IN THE MAIN CONFIG FILE +def config_reports(_config, _logger, _factory): + if _config['REPORTS']['REPORT']: + def reporting_loop(_logger, _server): + _logger.debug('Periodic reporting loop started') + _server.send_config() + _server.send_bridge() + + _logger.info('HBlink TCP reporting server configured') + + 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']) + + return report_server + # Import Bridging rules # Note: A stanza *must* exist for any MASTER or CLIENT configured in the main # configuration file and listed as "active". It can be empty, @@ -173,11 +198,13 @@ def rule_timer_loop(): else: logger.debug('Conference Bridge NO ACTION: System: %s, Bridge: %s, TS: %s, TGID: %s', _system['SYSTEM'], _bridge, _system['TS'], int_id(_system['TGID'])) + if CONFIG['REPORTS']['REPORT']: + report_server.send_clients('bridge updated') class routerSYSTEM(HBSYSTEM): - def __init__(self, _name, _config, _logger): - HBSYSTEM.__init__(self, _name, _config, _logger) + def __init__(self, _name, _config, _logger, _report): + HBSYSTEM.__init__(self, _name, _config, _logger, _report) # Status information for the system, TS1 & TS2 # 1 & 2 are "timeslot" @@ -251,6 +278,9 @@ class routerSYSTEM(HBSYSTEM): self.STATUS['RX_START'] = pkt_time self._logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_radio_id, peer_ids), int_id(_radio_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot) + if CONFIG['REPORTS']['REPORT']: + self._report.send_bridgeEvent('({}) *CALL START* STREAM ID: {} SUB: {} ({}) REPEATER: {} ({}) TGID {} ({}), TS {}'.format(\ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_radio_id, peer_ids), int_id(_radio_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot)) # If we can, use the LC from the voice header as to keep all options intact if _frame_type == hb_const.HBPF_DATA_SYNC and _dtype_vseq == hb_const.HBPF_SLT_VHEAD: @@ -353,6 +383,9 @@ class routerSYSTEM(HBSYSTEM): call_duration = pkt_time - self.STATUS['RX_START'] self._logger.info('(%s) *CALL END* STREAM ID: %s SUB: %s (%s) REPEATER: %s (%s) TGID %s (%s), TS %s, Duration: %s', \ self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_radio_id, peer_ids), int_id(_radio_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot, call_duration) + if CONFIG['REPORTS']['REPORT']: + self._report.send_bridgeEvent('({}) *CALL START* STREAM ID: {} SUB: {} ({}) REPEATER: {} ({}) TGID {} ({}), TS {}'.format(\ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_radio_id, peer_ids), int_id(_radio_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot)) # # Begin in-band signalling for call end. This has nothign to do with routing traffic directly. @@ -419,6 +452,18 @@ class routerSYSTEM(HBSYSTEM): self.STATUS[_slot]['RX_TIME'] = pkt_time self.STATUS[_slot]['RX_STREAM_ID'] = _stream_id +# +# Socket-based reporting section +# +class confbridgeReportFactory(reportFactory): + + 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) + #************************************************ # MAIN PROGRAM LOOP STARTS HERE @@ -494,11 +539,14 @@ if __name__ == '__main__': # Build the Access Control List ACL = build_acl('sub_acl') + # INITIALIZE THE REPORTING LOOP + report_server = config_reports(CONFIG, logger, confbridgeReportFactory) + # HBlink instance creation logger.info('HBlink \'hb_router.py\' (c) 2016 N0MJS & the K0USY Group - SYSTEM STARTING...') for system in CONFIG['SYSTEMS']: if CONFIG['SYSTEMS'][system]['ENABLED']: - systems[system] = routerSYSTEM(system, CONFIG, logger) + systems[system] = routerSYSTEM(system, CONFIG, logger, report_server) reactor.listenUDP(CONFIG['SYSTEMS'][system]['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['IP']) logger.debug('%s instance created: %s, %s', CONFIG['SYSTEMS'][system]['MODE'], system, systems[system]) diff --git a/hblink.py b/hblink.py index 884b53b..fac2e7e 100755 --- a/hblink.py +++ b/hblink.py @@ -64,7 +64,7 @@ __email__ = 'n0mjs@me.com' # Global variables used whether we are a module or __main__ systems = {} -# Timed loop used for reporting IPSC status +# Timed loop used for reporting HBP status # # REPORT BASED ON THE TYPE SELECTED IN THE MAIN CONFIG FILE def config_reports(_config, _logger, _factory): @@ -81,6 +81,8 @@ def config_reports(_config, _logger, _factory): reporting = task.LoopingCall(reporting_loop, _logger, report_server) reporting.start(_config['REPORTS']['REPORT_INTERVAL']) + + return report_server # Shut ourselves down gracefully by disconnecting from the masters and clients. @@ -132,11 +134,12 @@ class AMBE: #************************************************ class HBSYSTEM(DatagramProtocol): - def __init__(self, _name, _config, _logger): + def __init__(self, _name, _config, _logger, _report): # Define a few shortcuts to make the rest of the class more readable self._CONFIG = _config self._system = _name self._logger = _logger + self._report = _report self._config = self._CONFIG['SYSTEMS'][self._system] # Define shortcuts and generic function names based on the type of system we are @@ -587,13 +590,13 @@ if __name__ == '__main__': signal.signal(sig, sig_handler) # INITIALIZE THE REPORTING LOOP - config_reports(CONFIG, logger, reportFactory) + report_server = config_reports(CONFIG, logger, reportFactory) # HBlink instance creation logger.info('HBlink \'HBlink.py\' (c) 2016 N0MJS & the K0USY Group - SYSTEM STARTING...') for system in CONFIG['SYSTEMS']: if CONFIG['SYSTEMS'][system]['ENABLED']: - systems[system] = HBSYSTEM(system, CONFIG, logger) + systems[system] = HBSYSTEM(system, CONFIG, logger, report_server) reactor.listenUDP(CONFIG['SYSTEMS'][system]['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['IP']) logger.debug('%s instance created: %s, %s', CONFIG['SYSTEMS'][system]['MODE'], system, systems[system]) diff --git a/sub_acl.py b/sub_acl.py index 621409c..2133554 100644 --- a/sub_acl.py +++ b/sub_acl.py @@ -2,4 +2,4 @@ # Each entry may be a single radio id, or a hypenated range (e.g. 1-2999) # Format: # ACL = 'action:id|start-end|,id|start-end,....' -ACL = 'DENY:0-2999,4000000-9999999' \ No newline at end of file +ACL = 'DENY:0-2999,4000000-4000999' \ No newline at end of file