From 050aad7cb3d453e66a5b0f8ceb6b17de84b01991 Mon Sep 17 00:00:00 2001 From: Cort Buffington Date: Fri, 2 Feb 2018 14:14:30 -0600 Subject: [PATCH] HIGH PROFILE FIXES - Addresses Brandmeister disconnects. Random: * Commented out per-packet debug logger lines (uncomment locally when needed) Problems Fixed: CLIENT MODE: hblink.py hblink.py did not properly parse the radio_id in a MSTNAK message. We searched for "MSTN" - 4 characters, and neglected to parse the radio ID at offset 6, after "MSTNAK" instead of after 4, "MSTN".... rookie mistake: elif _command == 'MSTN': # Actually MSTNAK -- a NACK from the master - _radio_id = _data[4:8] + _radio_id = _data[6:10] hblink.py did not actually keep track of missed keep-alives correctly to reset a connection. This has probably been fixed. At worst, no more broken than it was. Would like to have some folks test it by breaking connectivty froma client to master and watch what happens. Appears to work now. --- hb_bridge_all.py | 4 ++-- hb_config.py | 1 + hblink.py | 21 ++++++++++++++------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/hb_bridge_all.py b/hb_bridge_all.py index 068c8a2..9d98c35 100755 --- a/hb_bridge_all.py +++ b/hb_bridge_all.py @@ -134,7 +134,7 @@ class bridgeallSYSTEM(HBSYSTEM): for _target in self._CONFIG['SYSTEMS']: if _target != self._system: systems[_target].send_system(_data) - self._logger.debug('(%s) Packet routed to system: %s', self._system, _target) + #self._logger.debug('(%s) Packet routed to system: %s', self._system, _target) # Final actions - Is this a voice terminator? @@ -228,4 +228,4 @@ if __name__ == '__main__': 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]) - reactor.run() \ No newline at end of file + reactor.run() diff --git a/hb_config.py b/hb_config.py index 2f3e1a3..110b493 100755 --- a/hb_config.py +++ b/hb_config.py @@ -121,6 +121,7 @@ def build_config(_config_file): 'CONNECTION': 'NO', # NO, RTPL_SENT, AUTHENTICATED, CONFIG-SENT, YES 'PINGS_SENT': 0, 'PINGS_ACKD': 0, + 'NUM_OUTSTANDING': 0, 'PING_OUTSTANDING': False, 'LAST_PING_TX_TIME': 0, 'LAST_PING_ACK_TIME': 0, diff --git a/hblink.py b/hblink.py index f7d4037..0d76aff 100755 --- a/hblink.py +++ b/hblink.py @@ -154,18 +154,23 @@ class HBSYSTEM(DatagramProtocol): # Aliased in __init__ to maintenance_loop if system is a client def client_maintenance_loop(self): self._logger.debug('(%s) Client 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'] == 'NO' or self._stats['CONNECTION'] == 'RTPL_SENT': + if self._stats['CONNECTION'] == 'NO' or self._stats['CONNECTION'] == 'RPTL_SENT' or self._stats['NUM_OUTSTANDING'] >= self._CONFIG['GLOBAL']['MAX_MISSED']: self._stats['PINGS_SENT'] = 0 self._stats['PINGS_ACKD'] = 0 - self._stats['CONNECTION'] = 'RTPL_SENT' + self._stats['NUM_OUTSTANDING'] = 0 + self._stats['PING_OUTSTANDING'] = False + self._stats['CONNECTION'] = 'RPTL_SENT' self.send_master('RPTL'+self._config['RADIO_ID']) self._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': self.send_master('RPTPING'+self._config['RADIO_ID']) + self._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._logger.debug('(%s) RPTPING Sent to Master. Pings Since Connected: %s', self._system, self._stats['PINGS_SENT']) + self._stats['PING_OUTSTANDING'] = True def send_clients(self, _packet): for _client in self._clients: @@ -230,7 +235,7 @@ class HBSYSTEM(DatagramProtocol): for _client in self._clients: if _client != _radio_id: self.send_client(_client, _data) - self._logger.debug('(%s) Packet on TS%s from %s (%s) for destination ID %s repeated to client: %s (%s) [Stream ID: %s]', self._system, _slot, self._clients[_radio_id]['CALLSIGN'], int_id(_radio_id), int_id(_dst_id), self._clients[_client]['CALLSIGN'], int_id(_client), int_id(_stream_id)) + #self._logger.debug('(%s) Packet on TS%s from %s (%s) for destination ID %s repeated to client: %s (%s) [Stream ID: %s]', self._system, _slot, self._clients[_radio_id]['CALLSIGN'], int_id(_radio_id), int_id(_dst_id), self._clients[_client]['CALLSIGN'], int_id(_client), int_id(_stream_id)) # Userland actions -- typically this is the function you subclass for an application self.dmrd_received(_radio_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data) @@ -381,14 +386,14 @@ class HBSYSTEM(DatagramProtocol): self.dmrd_received(_radio_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 - _radio_id = _data[4:8] + _radio_id = _data[6:10] if _radio_id == self._config['RADIO_ID']: # Validate the source and intended target - self._logger.warning('(%s) MSTNAK Received', self._system) + self._logger.warning('(%s) MSTNAK Received. Resetting connection to the Master.', self._system) self._stats['CONNECTION'] = 'NO' # Disconnect ourselves and re-register 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'] == 'RTPL_SENT': # If we've sent a login request... + if self._stats['CONNECTION'] == 'RPTL_SENT': # If we've sent a login request... _login_int32 = _data[6:10] self._logger.info('(%s) Repeater Login ACK Received with 32bit ID: %s', self._system, int_id(_login_int32)) _pass_hash = sha256(_login_int32+self._config['PASSPHRASE']).hexdigest() @@ -447,6 +452,8 @@ class HBSYSTEM(DatagramProtocol): elif _command == 'MSTP': # Actually MSTPONG -- a reply to RPTPING (send by client) if _data [7:11] == self._config['RADIO_ID']: + self._stats['PING_OUTSTANDING'] = False + self._stats['NUM_OUTSTANDING'] = 0 self._stats['PINGS_ACKD'] += 1 self._logger.debug('(%s) MSTPONG Received. Pongs Since Connected: %s', self._system, self._stats['PINGS_ACKD'])