Major Clean-Up!!!

Cleaned up many things:
Needless iteration during received packet parsing.
Grouping received packet re-requisite checking so that it can be done
once, not on each packet.
Removed some conversions where a number is converted twice just to be
compared.
This commit is contained in:
Cort Buffington 2013-10-21 20:54:51 -05:00
parent 800969bb39
commit f23780901b
2 changed files with 212 additions and 193 deletions

393
ipsc.py
View File

@ -92,7 +92,6 @@ except ImportError:
''' '''
ACTIVE_CALLS = [] ACTIVE_CALLS = []
NETWORK = {} NETWORK = {}
config = ConfigParser.ConfigParser() config = ConfigParser.ConfigParser()
@ -157,8 +156,6 @@ for section in config.sections():
#************************************************ #************************************************
def call_ctl_1(_network, _data): def call_ctl_1(_network, _data):
_src_sub = int(binascii.b2a_hex(_data[6:9]), 16)
_src_sub = get_info(_src_sub)
print('({}) Call Control Type 1 Packet Received From: {}' .format(_network, _src_sub)) print('({}) Call Control Type 1 Packet Received From: {}' .format(_network, _src_sub))
def call_ctl_2(_network, _data): def call_ctl_2(_network, _data):
@ -168,40 +165,44 @@ def call_ctl_3(_network, _data):
print('({}) Call Control Type 3 Packet Received' .format(_network)) print('({}) Call Control Type 3 Packet Received' .format(_network))
def xcmp_xnl(_network, _data): def xcmp_xnl(_network, _data):
_src_sub = int(binascii.b2a_hex(_data[6:9]), 16)
_src_sub = get_info(_src_sub)
print('({}) XCMP/XNL Packet Received From: {}' .format(_network, _src_sub)) print('({}) XCMP/XNL Packet Received From: {}' .format(_network, _src_sub))
def group_voice(_network, _data): def group_voice(_network, _src_sub, _dst_group, _call, _peerid, _data):
# _log = logger.debug # _log = logger.debug
_timestamp = int(time.time())
_time = time.strftime('%m/%d/%y %H:%M:%S')
_src_sub = int(binascii.b2a_hex(_data[6:9]), 16)
_dst_group = int(binascii.b2a_hex(_data[9:12]), 16)
_src_ipsc = int(binascii.b2a_hex(_data[1:5]), 16)
_call = binascii.b2a_hex(_data[17:18])
_dst_group = get_info(_dst_group) if _call == '\x00':
_src_ipsc = get_info(_src_ipsc)
_src_sub = get_info(_src_sub)
if _call == '00':
if (_network, 'Slot 1') not in ACTIVE_CALLS: if (_network, 'Slot 1') not in ACTIVE_CALLS:
_time = time.strftime('%m/%d/%y %H:%M:%S')
_dst_group = get_info(int(binascii.b2a_hex(_dst_group), 16))
_peerid = get_info(int(binascii.b2a_hex(_peerid), 16))
_src_sub = get_info(int(binascii.b2a_hex(_src_sub), 16))
ACTIVE_CALLS.append((_network, 'Slot 1')) ACTIVE_CALLS.append((_network, 'Slot 1'))
print('{} ({}) CALL START Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t1' .format(_time, _network, _src_ipsc, _src_sub, _dst_group)) print('{} ({}) CALL START Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t1' .format(_time, _network, _peerid, _src_sub, _dst_group))
if _call == '20': if _call == '\x20':
if (_network, 'Slot 2') not in ACTIVE_CALLS: if (_network, 'Slot 2') not in ACTIVE_CALLS:
_time = time.strftime('%m/%d/%y %H:%M:%S')
_dst_group = get_info(int(binascii.b2a_hex(_dst_group), 16))
_peerid = get_info(int(binascii.b2a_hex(_peerid), 16))
_src_sub = get_info(int(binascii.b2a_hex(_src_sub), 16))
ACTIVE_CALLS.append((_network, 'Slot 2')) ACTIVE_CALLS.append((_network, 'Slot 2'))
print('{} ({}) CALL START Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t2' .format(_time, _network, _src_ipsc, _src_sub, _dst_group)) print('{} ({}) CALL START Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t2' .format(_time, _network, _peerid, _src_sub, _dst_group))
if _call == '40': if _call == '\x40':
_time = time.strftime('%m/%d/%y %H:%M:%S')
_dst_group = get_info(int(binascii.b2a_hex(_dst_group), 16))
_peerid = get_info(int(binascii.b2a_hex(_peerid), 16))
_src_sub = get_info(int(binascii.b2a_hex(_src_sub), 16))
ACTIVE_CALLS.remove((_network, 'Slot 1')) ACTIVE_CALLS.remove((_network, 'Slot 1'))
print('{} ({}) CALL END Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t1 \a' .format(_time, _network, _src_ipsc, _src_sub, _dst_group)) print('{} ({}) CALL END Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t1 \a' .format(_time, _network, _peerid, _src_sub, _dst_group))
if _call == '60': if _call == '\x60':
_time = time.strftime('%m/%d/%y %H:%M:%S')
_dst_group = get_info(int(binascii.b2a_hex(_dst_group), 16))
_peerid = get_info(int(binascii.b2a_hex(_peerid), 16))
_src_sub = get_info(int(binascii.b2a_hex(_src_sub), 16))
ACTIVE_CALLS.remove((_network, 'Slot 2')) ACTIVE_CALLS.remove((_network, 'Slot 2'))
print('{} ({}) CALL END Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t2 \a' .format(_time, _network, _src_ipsc, _src_sub, _dst_group)) print('{} ({}) CALL END Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t2 \a' .format(_time, _network, _peerid, _src_sub, _dst_group))
''' '''
for source in NETWORK[_network]['RULES']['GROUP_VOICE']: for source in NETWORK[_network]['RULES']['GROUP_VOICE']:
@ -210,7 +211,7 @@ def group_voice(_network, _data):
_target = source['DST_NET'] _target = source['DST_NET']
_target_sock = NETWORK[_target]['MASTER']['IP'], NETWORK[_target]['MASTER']['PORT'] _target_sock = NETWORK[_target]['MASTER']['IP'], NETWORK[_target]['MASTER']['PORT']
# Re-Write the IPSC SRC to match the target network's ID # Re-Write the IPSC SRC to match the target network's ID
_data = _data.replace(_src_ipsc, NETWORK[_target]['LOCAL']['RADIO_ID']) _data = _data.replace(_peerid, NETWORK[_target]['LOCAL']['RADIO_ID'])
# Re-Write the destinaion Group ID # Re-Write the destinaion Group ID
_data = _data.replace(_src_group, source['DST_GROUP']) _data = _data.replace(_src_group, source['DST_GROUP'])
# Calculate and append the authentication hash for the target network... if necessary # Calculate and append the authentication hash for the target network... if necessary
@ -220,63 +221,62 @@ def group_voice(_network, _data):
send_to_ipsc(_target, _data) send_to_ipsc(_target, _data)
''' '''
def private_voice(_network, _data): def private_voice(_network, _src_sub, _dst_sub, _call, _peerid, _data):
# _log = logger.debug # _log = logger.debug
_timestamp = int(time.time())
_time = time.strftime('%m/%d/%y %H:%M:%S')
_src_sub = int(binascii.b2a_hex(_data[6:9]), 16)
_dst_sub = int(binascii.b2a_hex(_data[9:12]), 16)
_src_ipsc = int(binascii.b2a_hex(_data[1:5]), 16)
_call = binascii.b2a_hex(_data[17:18])
_dst_sub = get_info(_dst_sub) if _call == '\x00':
_src_ipsc = get_info(_src_ipsc)
_src_sub = get_info(_src_sub)
if _call == '00':
if (_network, 'Slot 1') not in ACTIVE_CALLS: if (_network, 'Slot 1') not in ACTIVE_CALLS:
_time = time.strftime('%m/%d/%y %H:%M:%S')
_dst_sub = get_info(int(binascii.b2a_hex(_dst_sub), 16))
_peerid = get_info(int(binascii.b2a_hex(_peerid), 16))
_src_sub = get_info(int(binascii.b2a_hex(_src_sub), 16))
ACTIVE_CALLS.append((_network, 'Slot 1')) ACTIVE_CALLS.append((_network, 'Slot 1'))
print('{} ({}) CALL START Private Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t1' .format(_time, _network, _src_ipsc, _src_sub, _dst_sub)) print('{} ({}) CALL START Private Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t1' .format(_time, _network, _peerid, _src_sub, _dst_sub))
if _call == '20': if _call == '\x20':
if (_network, 'Slot 2') not in ACTIVE_CALLS: if (_network, 'Slot 2') not in ACTIVE_CALLS:
_time = time.strftime('%m/%d/%y %H:%M:%S')
_dst_sub = get_info(int(binascii.b2a_hex(_dst_sub), 16))
_peerid = get_info(int(binascii.b2a_hex(_peerid), 16))
_src_sub = get_info(int(binascii.b2a_hex(_src_sub), 16))
ACTIVE_CALLS.append((_network, 'Slot 2')) ACTIVE_CALLS.append((_network, 'Slot 2'))
print('({} {}) CALL START Private Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t2' .format(_time, _network, _src_ipsc, _src_sub, _dst_sub)) print('({} {}) CALL START Private Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t2' .format(_time, _network, _peerid, _src_sub, _dst_sub))
if _call == '40': if _call == '\x40':
_time = time.strftime('%m/%d/%y %H:%M:%S')
_dst_sub = get_info(int(binascii.b2a_hex(_dst_sub), 16))
_peerid = get_info(int(binascii.b2a_hex(_peerid), 16))
_src_sub = get_info(int(binascii.b2a_hex(_src_sub), 16))
ACTIVE_CALLS.remove((_network, 'Slot 1')) ACTIVE_CALLS.remove((_network, 'Slot 1'))
print('{} ({}) CALL END Private Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t1 \a' .format(_time, _network, _src_ipsc, _src_sub, _dst_sub)) print('{} ({}) CALL END Private Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t1 \a' .format(_time, _network, _peerid, _src_sub, _dst_sub))
if _call == '60': if _call == '\x60':
_time = time.strftime('%m/%d/%y %H:%M:%S')
_dst_sub = get_info(int(binascii.b2a_hex(_dst_sub), 16))
_peerid = get_info(int(binascii.b2a_hex(_peerid), 16))
_src_sub = get_info(int(binascii.b2a_hex(_src_sub), 16))
ACTIVE_CALLS.remove((_network, 'Slot 2')) ACTIVE_CALLS.remove((_network, 'Slot 2'))
print('{} ({}) CALL END Private Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t2 \a' .format(_time, _network, _src_ipsc, _src_sub, _dst_sub)) print('{} ({}) CALL END Private Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t2 \a' .format(_time, _network, _peerid, _src_sub, _dst_sub))
def group_data(_network, _data): def group_data(_network, _src_sub, _dst_sub, _call, _peerid, _data):
_src_sub = int(binascii.b2a_hex(_data[6:9]), 16)
_dst_sub = int(binascii.b2a_hex(_data[9:12]), 16)
_src_ipsc = int(binascii.b2a_hex(_data[1:5]), 16)
_call = binascii.b2a_hex(_data[17:18])
_dst_sub = get_info(_dst_sub) _dst_sub = get_info(_dst_sub)
_src_ipsc = get_info(_src_ipsc) _peerid = get_info(_peerid)
_src_sub = get_info(_src_sub) _src_sub = get_info(_src_sub)
print('({}) Group Data Packet Received From: {}' .format(_network, _src_sub)) print('({}) Group Data Packet Received From: {}' .format(_network, _src_sub))
def private_data(_network, _data): def private_data(__network, _src_sub, _dst_sub, _call, _peerid, _data):
_src_sub = int(binascii.b2a_hex(_data[6:9]), 16)
_dst_sub = int(binascii.b2a_hex(_data[9:12]), 16)
_src_ipsc = int(binascii.b2a_hex(_data[1:5]), 16)
_call = binascii.b2a_hex(_data[17:18])
_dst_sub = get_info(_dst_sub) _dst_sub = get_info(_dst_sub)
_src_ipsc = get_info(_src_ipsc) _peerid = get_info(_peerid)
_src_sub = get_info(_src_sub) _src_sub = get_info(_src_sub)
print('({}) Private Data Packet Received From: {} To: {}' .format(_network, _src_sub, _dst_sub)) print('({}) Private Data Packet Received From: {} To: {}' .format(_network, _src_sub, _dst_sub))
def unknown_message(_network, _packettype, _data): def unknown_message(_network, _packettype, _data):
_src_ipsc = int(binascii.b2a_hex(_data[1:5]), 16) _peerid = binascii.b2a_hex(_data[1:5])
_src_ipsc = get_info(_src_ipsc) _packettype = binascii.b2a_hex(_packettype)
print("({}) Unknown message type encountered, Packet Type: {} From: {} " .format(_network, _packettype, _src_ipsc)) _peerid = get_info(_peerid)
print("({}) Unknown message type encountered, Packet Type: {} From: {} " .format(_network, _packettype, _peerid))
print(binascii.b2a_hex(_data)) print(binascii.b2a_hex(_data))
@ -302,7 +302,7 @@ def get_info(_id):
return id[0] return id[0]
return _id return _id
# Remove the hash from a paket and return the payload # Remove the hash from a packet and return the payload
# #
def strip_hash(_data): def strip_hash(_data):
# _log = logger.debug # _log = logger.debug
@ -324,7 +324,7 @@ def valid_peer(_peer_list, _peerid):
# Determine if the provided master ID is valid for the provided network # Determine if the provided master ID is valid for the provided network
# #
def valid_master(_network, _peerid): def valid_master(_network, _peerid):
# _log = logger.debug # _log = logger.warning
if NETWORK[_network]['MASTER']['RADIO_ID'] == _peerid: if NETWORK[_network]['MASTER']['RADIO_ID'] == _peerid:
# _log('Master ID is Valid: %s', binascii.b2a_hex(_peerid)) # _log('Master ID is Valid: %s', binascii.b2a_hex(_peerid))
return True return True
@ -370,8 +370,6 @@ def de_register_peer(_network, _peerid):
# #
def process_peer_list(_data, _network, _peer_list): def process_peer_list(_data, _network, _peer_list):
# _log = logger.debug # _log = logger.debug
# Set the status flag to indicate we have recieved a Peer List
NETWORK[_network]['MASTER']['STATUS']['PEER-LIST'] = True
# Determine the length of the peer list for the parsing iterator # Determine the length of the peer list for the parsing iterator
_peer_list_length = int(binascii.b2a_hex(_data[5:7]), 16) _peer_list_length = int(binascii.b2a_hex(_data[5:7]), 16)
# Record the number of peers in the data structure... we'll use it later (11 bytes per peer entry) # Record the number of peers in the data structure... we'll use it later (11 bytes per peer entry)
@ -508,9 +506,7 @@ class IPSC(DatagramProtocol):
# Spendy than iterating a list of dictionaries... Maybe I'll find a better way in the future. Also # Spendy than iterating a list of dictionaries... Maybe I'll find a better way in the future. Also
# We have to know when we have a new peer list, so a variable to indicate we do (or don't) # We have to know when we have a new peer list, so a variable to indicate we do (or don't)
# #
self._peer_list = [] self._peer_list = []
self._peer_list_new = False
args = () args = ()
# Packet 'constructors' - builds the necessary control packets for this IPSC instance. # Packet 'constructors' - builds the necessary control packets for this IPSC instance.
@ -529,6 +525,7 @@ class IPSC(DatagramProtocol):
# If we didn't get called correctly, log it! # If we didn't get called correctly, log it!
# #
logger.error('(%s) Unexpected arguments found.', self._network) logger.error('(%s) Unexpected arguments found.', self._network)
sys.exit()
# This is called by REACTOR when it starts, We use it to set up the timed # This is called by REACTOR when it starts, We use it to set up the timed
@ -546,25 +543,22 @@ class IPSC(DatagramProtocol):
# Take a packet to be SENT, calcualte auth hash and return the whole thing # Take a packet to be SENT, calcualte auth hash and return the whole thing
# #
def hashed_packet(self, _key, _data): def hashed_packet(self, _key, _data):
# _log = logger.debug
_hash = binascii.a2b_hex((hmac.new(_key,_data,hashlib.sha1)).hexdigest()[:20]) _hash = binascii.a2b_hex((hmac.new(_key,_data,hashlib.sha1)).hexdigest()[:20])
# _log('Hash for: %s is %s', binascii.b2a_hex(_data), binascii.b2a_hex(_hash)
return (_data + _hash) return (_data + _hash)
# Take a RECEIVED packet, calculate the auth hash and verify authenticity # Take a RECEIVED packet, calculate the auth hash and verify authenticity
# #
def validate_auth(self, _key, _data): def validate_auth(self, _key, _data):
# _log = logger.debug _log = logger.info
_payload = strip_hash(_data) _payload = strip_hash(_data)
_hash = _data[-10:] _hash = _data[-10:]
_chk_hash = binascii.a2b_hex((hmac.new(_key,_payload,hashlib.sha1)).hexdigest()[:20]) _chk_hash = binascii.a2b_hex((hmac.new(_key,_payload,hashlib.sha1)).hexdigest()[:20])
if _chk_hash == _hash: if _chk_hash == _hash:
# _log(' AUTH: Valid - Payload: %s, Hash: %s', binascii.b2a_hex(_payload), binascii.b2a_hex(_hash))
return True return True
else: else:
# _log(' AUTH: Invalid - Payload: %s, Hash: %s', binascii.b2a_hex(_payload), binascii.b2a_hex(_hash)) _log('AUTHENTICATION FAILURE: \n\t Payload: %s\n\t Hash: %s', binascii.b2a_hex(_payload), binascii.b2a_hex(_hash))
return False return False
@ -577,6 +571,7 @@ class IPSC(DatagramProtocol):
# print_peer_list(self._network) # print_peer_list(self._network)
# If the master isn't connected, we have to do that before we can do anything else! # If the master isn't connected, we have to do that before we can do anything else!
#
if self._master_stat['CONNECTED'] == False: if self._master_stat['CONNECTED'] == False:
reg_packet = self.hashed_packet(self._local['AUTH_KEY'], self.MASTER_REG_REQ_PKT) reg_packet = self.hashed_packet(self._local['AUTH_KEY'], self.MASTER_REG_REQ_PKT)
self.transport.write(reg_packet, (self._master_sock)) self.transport.write(reg_packet, (self._master_sock))
@ -601,16 +596,21 @@ class IPSC(DatagramProtocol):
self._master_stat['KEEP_ALIVES_OUTSTANDING'] += 1 self._master_stat['KEEP_ALIVES_OUTSTANDING'] += 1
else: else:
# This is bad. If we get this message, probably need to restart the program. # This is bad. If we get this message, we need to reset the state and try again
logger.error('->> (%s) Master in UNKOWN STATE:%s:%s', self._network, self._master_sock) logger.error('->> (%s) Master in UNKOWN STATE:%s:%s', self._network, self._master_sock)
self._master_stat['CONNECTED'] == False
# If the master is connected and we don't have a peer-list yet....
# If the master is connected and we don't have a peer-list yet....
#
if ((self._master_stat['CONNECTED'] == True) and (self._master_stat['PEER-LIST'] == False)): if ((self._master_stat['CONNECTED'] == True) and (self._master_stat['PEER-LIST'] == False)):
# Ask the master for a peer-list # Ask the master for a peer-list
peer_list_req_packet = self.hashed_packet(self._local['AUTH_KEY'], self.PEER_LIST_REQ_PKT) peer_list_req_packet = self.hashed_packet(self._local['AUTH_KEY'], self.PEER_LIST_REQ_PKT)
self.transport.write(peer_list_req_packet, (self._master_sock)) self.transport.write(peer_list_req_packet, (self._master_sock))
# If we do ahve a peer-list, we need to register with the peers and send keep-alives... # If we do ahve a peer-list, we need to register with the peers and send keep-alives...
#
if (self._master_stat['PEER-LIST'] == True): if (self._master_stat['PEER-LIST'] == True):
# Iterate the list of peers... so we do this for each one. # Iterate the list of peers... so we do this for each one.
for peer in (self._peers): for peer in (self._peers):
@ -641,6 +641,9 @@ class IPSC(DatagramProtocol):
peer['STATUS']['KEEP_ALIVES_SENT'] += 1 peer['STATUS']['KEEP_ALIVES_SENT'] += 1
peer['STATUS']['KEEP_ALIVES_OUTSTANDING'] += 1 peer['STATUS']['KEEP_ALIVES_OUTSTANDING'] += 1
# For public display of information, etc. - anything not part of internal logging/diagnostics
#
def _notify_event(self, network, event, info): def _notify_event(self, network, event, info):
""" """
Used internally whenever an event happens that may be useful to notify the outside world about. Used internally whenever an event happens that may be useful to notify the outside world about.
@ -650,8 +653,8 @@ class IPSC(DatagramProtocol):
info: dict, in the interest of accomplishing as much as possible without code changes. info: dict, in the interest of accomplishing as much as possible without code changes.
The dict will typically contain a peer_id so the origin of the event is known. The dict will typically contain a peer_id so the origin of the event is known.
""" """
pass pass
return
#************************************************ #************************************************
# RECEIVED DATAGRAM - ACT IMMEDIATELY!!! # RECEIVED DATAGRAM - ACT IMMEDIATELY!!!
@ -669,147 +672,151 @@ class IPSC(DatagramProtocol):
_peerid = data[1:5] _peerid = data[1:5]
_dec_peerid = int(binascii.b2a_hex(_peerid), 16) _dec_peerid = int(binascii.b2a_hex(_peerid), 16)
# First action: if Authentication is active, authenticate the packet # Authenticate the packet
# if self.validate_auth(self._local['AUTH_KEY'], data) == False:
if bool(self._local['AUTH_KEY']) == True: logger.warning('(%s) AuthError: IPSC packet failed authentication. Type %s: Peer ID: %s', self._network, binascii.b2a_hex(_packettype), _dec_peerid)
# Validate return
if self.validate_auth(self._local['AUTH_KEY'], data) == False:
logger.warning('(%s) AuthError: IPSC packet failed authentication. Type %s: Peer ID: %s', self._network, binascii.b2a_hex(_packettype), _dec_peerid) # Strip the hash, we won't need it anymore
return data = strip_hash(data)
# Strip the hash, we won't need it anymore
data = strip_hash(data)
# Packets generated by "users" that are the most common should come first for efficiency. # Packets types that must be originated from a peer (including master peer)
# if (_packettype in ANY_PEER_REQUIRED):
if (_packettype == GROUP_VOICE):
# Don't take action unless it's from a valid peer (including the master, of course)
if not(valid_master(self._network, _peerid) == False or valid_peer(self._peer_list, _peerid) == False): if not(valid_master(self._network, _peerid) == False or valid_peer(self._peer_list, _peerid) == False):
logger.warning('(%s) PeerError: Peer not in peer-list: %s', self._network, _dec_peerid) logger.warning('(%s) PeerError: Peer not in peer-list: %s', self._network, _dec_peerid)
return return
self._notify_event(self._network, 'group_voice', {'peer_id': _dec_peerid})
group_voice(self._network, data) # User, as in "subscriber" generated packets - a.k.a someone trasmitted
if (_packettype in USER_PACKETS):
# Extract commonly used items from the packet header
_src_sub = data[6:9]
_dst_sub = data[9:12]
_call = data[17:18]
# User Voice and Data Call Types:
if (_packettype == GROUP_VOICE):
self._notify_event(self._network, 'group_voice', {'peer_id': _dec_peerid})
group_voice(self._network, _src_sub, _dst_sub, _call, _peerid, data)
return
elif (_packettype == PVT_VOICE):
self._notify_event(self._network, 'private_voice', {'peer_id': _dec_peerid})
private_voice(self._network, _src_sub, _dst_sub, _call, _peerid, data)
return
elif (_packettype == GROUP_DATA):
self._notify_event(self._network, 'group_data', {'peer_id': _dec_peerid})
group_data(self._network, _src_sub, _dst_sub, _call, _peerid, data)
return
elif (_packettype == PVT_DATA):
self._notify_event(self._network, 'private_voice', {'peer_id': _dec_peerid})
private_data(self._network, _src_sub, _dst_sub, _call, _peerid, data)
return
return
# Other peer-required types that we don't do much or anything with yet
elif (_packettype == XCMP_XNL):
xcmp_xnl(self._network, data)
return
elif (_packettype == CALL_CTL_1):
call_ctl_1(self._network, data)
return
elif (_packettype == CALL_CTL_2):
call_ctl_2(self._network, data)
return
elif (_packettype == CALL_CTL_3):
call_ctl_3(self._network, data)
return
# Connection maintenance packets that fall into this category
elif (_packettype == DE_REG_REQ):
de_register_peer(self._network, _peerid)
logger.warning('<<- (%s) Peer De-Registration Request From:%s:%s', self._network, host, port)
return
elif (_packettype == DE_REG_REPLY):
logger.warning('<<- (%s) Peer De-Registration Reply From:%s:%s', self._network, host, port)
return
elif (_packettype == RPT_WAKE_UP):
logger.warning('<<- (%s) Repeater Wake-Up Packet From:%s:%s', self._network, host, port)
return
return
# IPSC keep alives, master and peer, come next in processing priority # Packets types that must be originated from a peer
# if (_packettype in PEER_REQUIRED):
elif (_packettype == PEER_ALIVE_REQ):
# We should not answer a keep-alive request from a peer we don't know about!
if valid_peer(self._peer_list, _peerid) == False: if valid_peer(self._peer_list, _peerid) == False:
logger.warning('(%s) PeerError: Peer %s not in peer-list: %s', self._network, _dec_peerid, self._peer_list) logger.warning('(%s) PeerError: Peer %s not in peer-list: %s', self._network, _dec_peerid, self._peer_list)
return return
# Generate a hashed paket from our template and send it. # Packets we send...
peer_alive_reply_packet = self.hashed_packet(self._local['AUTH_KEY'], self.PEER_ALIVE_REPLY_PKT) if (_packettype == PEER_ALIVE_REQ):
self._notify_event(self._network, 'peer_keepalive', {'peer_id': _dec_peerid}) # Generate a hashed paket from our template and send it.
self.transport.write(peer_alive_reply_packet, (host, port)) peer_alive_reply_packet = self.hashed_packet(self._local['AUTH_KEY'], self.PEER_ALIVE_REPLY_PKT)
self.transport.write(peer_alive_reply_packet, (host, port))
elif (_packettype == MASTER_ALIVE_REPLY): return
# We should not accept keep-alive reply from someone claming to be a master who isn't!
if valid_master(self._network, _peerid) == False: elif (_packettype == PEER_REG_REQ):
logger.warning('(%s) PeerError: Peer %s not in peer-list: %s', self._network, _dec_peerid, self._peer_list) peer_reg_reply_packet = self.hashed_packet(self._local['AUTH_KEY'], self.PEER_REG_REPLY_PKT)
self.transport.write(peer_reg_reply_packet, (host, port))
return
# Packets we recieve...
elif (_packettype == PEER_ALIVE_REPLY):
for peer in self._config['PEERS']:
if peer['RADIO_ID'] == _peerid:
peer['STATUS']['KEEP_ALIVES_OUTSTANDING'] = 0
return return
# logger.debug('<<- (%s) Master Keep-alive Reply From: %s \t@ IP: %s:%s', self._network, _dec_peerid, host, port)
# This action is so simple, it doesn't require a callback function, master is responding, we're good.
self._master_stat['KEEP_ALIVES_OUTSTANDING'] = 0
elif (_packettype == PEER_ALIVE_REPLY): elif (_packettype == PEER_REG_REPLY):
# Find the peer in our list of peers... for peer in self._config['PEERS']:
for peer in self._config['PEERS']: if peer['RADIO_ID'] == _peerid:
if peer['RADIO_ID'] == _peerid: peer['STATUS']['CONNECTED'] = True
# No callback funcntion needed, set the outstanding keepalives to 0, and move on. return
peer['STATUS']['KEEP_ALIVES_OUTSTANDING'] = 0 return
# Packets types that must be originated from a Master
if (_packettype in MASTER_REQUIRED):
if valid_master(self._network, _peerid) == False:
logger.warning('(%s) PeerError: Master %s is invalid: %s', self._network, _dec_peerid, self._peer_list)
return
if (_packettype == MASTER_ALIVE_REPLY):
# This action is so simple, it doesn't require a callback function, master is responding, we're good.
self._master_stat['KEEP_ALIVES_OUTSTANDING'] = 0
return
elif (_packettype == PEER_LIST_REPLY):
NETWORK[self._network]['MASTER']['STATUS']['PEER-LIST'] = True
if len(data) > 18:
self._peer_list = process_peer_list(data, self._network, self._peer_list)
return
return
# Registration requests and replies are infrequent, but important. Peer lists can go here too as a part
# of the registration process.
#
elif (_packettype == MASTER_REG_REQ):
# We can't operate as a master as of now, so we should never receive one of these.
# logger.debug('<<- (%s) Master Registration Packet Recieved', self._network)
pass
# When we hear from the maseter, record it's ID, flag that we're connected, and reset the dead counter. # When we hear from the maseter, record it's ID, flag that we're connected, and reset the dead counter.
elif (_packettype == MASTER_REG_REPLY): elif (_packettype == MASTER_REG_REPLY):
self._master['RADIO_ID'] = _peerid self._master['RADIO_ID'] = _peerid
self._master_stat['CONNECTED'] = True self._master_stat['CONNECTED'] = True
self._master_stat['KEEP_ALIVES_OUTSTANDING'] = 0 self._master_stat['KEEP_ALIVES_OUTSTANDING'] = 0
return
# Answer a peer registration request -- simple, no callback runction needed # We know about these types, but absolutely don't take an action
elif (_packettype == PEER_REG_REQ): elif (_packettype == MASTER_REG_REQ):
if valid_peer(self._peer_list, _peerid): # We can't operate as a master as of now, so we should never receive one of these.
peer_reg_reply_packet = self.hashed_packet(self._local['AUTH_KEY'], self.PEER_REG_REPLY_PKT) # logger.debug('<<- (%s) Master Registration Packet Recieved', self._network)
self.transport.write(peer_reg_reply_packet, (host, port)) return
self._notify_event(self._network, 'peer_registration', {'peer_id': _dec_peerid})
elif (_packettype == PEER_REG_REPLY):
self._notify_event(self._network, 'peer_registration_reply', {'peer_id': _dec_peerid})
for peer in self._config['PEERS']:
if peer['RADIO_ID'] == _peerid:
peer['STATUS']['CONNECTED'] = True
elif (_packettype == PEER_LIST_REPLY):
if len(data) > 18:
self._peer_list = process_peer_list(data, self._network, self._peer_list)
else:
NETWORK[self._network]['MASTER']['STATUS']['PEER-LIST'] = True
elif (_packettype == DE_REG_REQ):
de_register_peer(self._network, _peerid)
logger.warning('<<- (%s) Peer De-Registration Request From:%s:%s', self._network, host, port)
elif (_packettype == DE_REG_REPLY):
logger.warning('<<- (%s) Peer De-Registration Reply From:%s:%s', self._network, host, port)
elif (_packettype == RPT_WAKE_UP):
logger.warning('<<- (%s) Repeater Wake-Up Packet From:%s:%s', self._network, host, port)
# Other "user" related packet types that we don't do much or anything with yet
#
elif (_packettype == PVT_VOICE):
if not(valid_master(self._network, _peerid) == False or valid_peer(self._peer_list, _peerid) == False):
logger.warning('(%s) PeerError: Peer not in peer-list: %s', self._network, _dec_peerid)
return
private_voice(self._network, data)
elif (_packettype == GROUP_DATA):
if not(valid_master(self._network, _peerid) == False or valid_peer(self._peer_list, _peerid) == False):
logger.warning('(%s) PeerError: Peer not in peer-list: %s', self._network, _dec_peerid)
return
group_data(self._network, data)
elif (_packettype == PVT_DATA):
if not(valid_master(self._network, _peerid) == False or valid_peer(self._peer_list, _peerid) == False):
logger.warning('(%s) PeerError: Peer not in peer-list: %s', self._network, _dec_peerid)
return
private_data(self._network, data)
elif (_packettype == XCMP_XNL): # NOTE: We currently indicate we are not XCMP/XNL capable!
if not(valid_master(self._network, _peerid) == False or valid_peer(self._peer_list, _peerid) == False):
logger.warning('(%s) PeerError: Peer not in peer-list: %s', self._network, _dec_peerid)
return
xcmp_xnl(self._network, data)
elif (_packettype == CALL_CTL_1):
if not(valid_master(self._network, _peerid) == False or valid_peer(self._peer_list, _peerid) == False):
logger.warning('(%s) PeerError: Peer not in peer-list: %s', self._network, _dec_peerid)
return
call_ctl_1(self._network, data)
elif (_packettype == CALL_CTL_2):
if not(valid_master(self._network, _peerid) == False or valid_peer(self._peer_list, _peerid) == False):
logger.warning('(%s) PeerError: Peer not in peer-list: %s', self._network, _dec_peerid)
return
call_ctl_2(self._network, data)
elif (_packettype == CALL_CTL_3):
if not(valid_master(self._network, _peerid) == False or valid_peer(self._peer_list, _peerid) == False):
logger.warning('(%s) PeerError: Peer not in peer-list: %s', self._network, _dec_peerid)
return
call_ctl_3(self._network, data)
# If there's a packet type we don't know aobut, it should be logged so we can figure it out and take an appropriate action! # If there's a packet type we don't know aobut, it should be logged so we can figure it out and take an appropriate action!
else: else:
unknown_message(self._network, _packettype, data) unknown_message(self._network, _packettype, data)
return
#************************************************ #************************************************
# Derived Class # Derived Class

View File

@ -45,6 +45,18 @@ LINK_TYPE_IPSC = b'\x04'
# IPSC Version and Link Type are Used for a 4-byte version field in registration packets # IPSC Version and Link Type are Used for a 4-byte version field in registration packets
IPSC_VER = LINK_TYPE_IPSC + IPSC_VER_19 + LINK_TYPE_IPSC + IPSC_VER_17 IPSC_VER = LINK_TYPE_IPSC + IPSC_VER_19 + LINK_TYPE_IPSC + IPSC_VER_17
# Packets that must originate from a peer (or master peer)
ANY_PEER_REQUIRED = [GROUP_VOICE, PVT_VOICE, GROUP_DATA, PVT_DATA, CALL_CTL_1, CALL_CTL_2, CALL_CTL_3, XCMP_XNL, RPT_WAKE_UP, DE_REG_REQ]
# Packets that must originate from a non-master peer
PEER_REQUIRED = [PEER_ALIVE_REQ, PEER_ALIVE_REPLY, PEER_REG_REQ, PEER_REG_REPLY]
# Packets that must originate from a master peer
MASTER_REQUIRED = [PEER_LIST_REPLY, MASTER_ALIVE_REPLY]
# User-Generated Packet Types
USER_PACKETS = [GROUP_VOICE, PVT_VOICE, GROUP_DATA, PVT_DATA]
# Conditions for accepting certain types of messages... the cornerstone of a secure IPSC system :) # Conditions for accepting certain types of messages... the cornerstone of a secure IPSC system :)
''' '''
REQ_VALID_PEER = [ REQ_VALID_PEER = [