From 1331726028cf0f248a10ccbbb605a6c7d0465e9a Mon Sep 17 00:00:00 2001 From: Cort Buffington Date: Tue, 29 Oct 2013 07:09:18 -0500 Subject: [PATCH] Add first two applications As of now, dmrlink.py is only a behind the scenes worker... It's just the base class to take care of link establishment and maintenance. Applications, such as bridging or logging will now be in their own files and inherit from dmrlink.py --- bridge.py | 77 +++++++++++++++++++++++++++++++++++++++++++++ log.py | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 bridge.py create mode 100644 log.py diff --git a/bridge.py b/bridge.py new file mode 100644 index 0000000..98ddf69 --- /dev/null +++ b/bridge.py @@ -0,0 +1,77 @@ +# Copyright (c) 2013 Cortney T. Buffington, N0MJS n0mjs@me.com +# +# This work is licensed under the Creative Commons Attribution-ShareAlike +# 3.0 Unported License.To view a copy of this license, visit +# http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to +# Creative Commons, 444 Castro Street, Suite 900, Mountain View, +# California, 94041, USA. + +from __future__ import print_function +from twisted.internet.protocol import DatagramProtocol +from twisted.internet import reactor +from twisted.internet import task + +import binascii +import dmrlink +from dmrlink import IPSC, UnauthIPSC, NETWORK, networks, get_info + +class bridgeIPSC(IPSC): + + def __init__(self, *args, **kwargs): + IPSC.__init__(self, *args, **kwargs) + self.ACTIVE_CALLS = [] + + def datagramReceived(self, data, (host, port)): + print(binascii.b2a_hex(data)) + + + #************************************************ + # CALLBACK FUNCTIONS FOR USER PACKET TYPES + #************************************************ + + def call_ctl_1(self, _network, _data): + pass + + def call_ctl_2(self, _network, _data): + pass + + def call_ctl_3(self, _network, _data): + pass + + def xcmp_xnl(self, _network, _data): + pass + + def group_voice(self, _network, _src_sub, _dst_sub, _ts, _end, _peerid, _data): + for source in NETWORK[_network]['RULES']['GROUP_VOICE']: + # Matching for rules is against the Destination Group in the SOURCE packet (SRC_GROUP) + if source['SRC_GROUP'] == _src_group: + _target = source['DST_NET'] + _target_sock = NETWORK[_target]['MASTER']['IP'], NETWORK[_target]['MASTER']['PORT'] + # Re-Write the IPSC SRC to match the target network's ID + _data = _data.replace(_peerid, NETWORK[_target]['LOCAL']['RADIO_ID']) + # Re-Write the destinaion Group ID + _data = _data.replace(_src_group, source['DST_GROUP']) + # Calculate and append the authentication hash for the target network... if necessary + if NETWORK[_target]['LOCAL']['AUTH_KEY'] == True: + _data = hashed_packet(NETWORK[_target]['LOCAL']['AUTH_KEY'], _data) + # Send the packet to all peers in the target IPSC + send_to_ipsc(_target, _data) + + def private_voice(self, _network, _src_sub, _dst_sub, _ts, _end, _peerid, _data): + pass + + def group_data(self, _network, _src_sub, _dst_sub, _ts, _end, _peerid, _data): + pass + + def private_data(self, _network, _src_sub, _dst_sub, _ts, _end, _peerid, _data): + pass + + +for ipsc_network in NETWORK: + if (NETWORK[ipsc_network]['LOCAL']['ENABLED']): + if NETWORK[ipsc_network]['LOCAL']['AUTH_ENABLED'] == True: + networks[ipsc_network] = bridgeIPSC(ipsc_network) + else: + networks[ipsc_network] = UnauthIPSC(ipsc_network) + reactor.listenUDP(NETWORK[ipsc_network]['LOCAL']['PORT'], networks[ipsc_network]) +reactor.run() \ No newline at end of file diff --git a/log.py b/log.py new file mode 100644 index 0000000..8cdaa1d --- /dev/null +++ b/log.py @@ -0,0 +1,94 @@ +# Copyright (c) 2013 Cortney T. Buffington, N0MJS n0mjs@me.com +# +# This work is licensed under the Creative Commons Attribution-ShareAlike +# 3.0 Unported License.To view a copy of this license, visit +# http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to +# Creative Commons, 444 Castro Street, Suite 900, Mountain View, +# California, 94041, USA. + +from __future__ import print_function +from twisted.internet.protocol import DatagramProtocol +from twisted.internet import reactor +from twisted.internet import task + +import time +import binascii +import dmrlink +from dmrlink import IPSC, UnauthIPSC, NETWORK, networks, get_info, int_id + +class logIPSC(IPSC): + def __init__(self, *args, **kwargs): + IPSC.__init__(self, *args, **kwargs) + self.ACTIVE_CALLS = [] + + #************************************************ + # CALLBACK FUNCTIONS FOR USER PACKET TYPES + #************************************************ + + def call_ctl_1(self, _network, _data): + print('({}) Call Control Type 1 Packet Received From: {}' .format(_network, _src_sub)) + + def call_ctl_2(self, _network, _data): + print('({}) Call Control Type 2 Packet Received' .format(_network)) + + def call_ctl_3(self, _network, _data): + print('({}) Call Control Type 3 Packet Received' .format(_network)) + + def xcmp_xnl(self, _network, _data): + print('({}) XCMP/XNL Packet Received From: {}' .format(_network, _src_sub)) + + def group_voice(self, _network, _src_sub, _dst_sub, _ts, _end, _peerid, _data): + # _log = logger.debug + if (_ts not in self.ACTIVE_CALLS) or _end: + _time = time.strftime('%m/%d/%y %H:%M:%S') + _dst_sub = get_info(int_id(_dst_sub)) + _peerid = get_info(int_id(_peerid)) + _src_sub = get_info(int_id(_src_sub)) + if not _end: self.ACTIVE_CALLS.append(_ts) + if _end: self.ACTIVE_CALLS.remove(_ts) + + if _ts: _ts = 2 + else: _ts = 1 + if _end: _end = 'END' + else: _end = 'START' + + print('{} ({}) Call {} Group Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t{}' .format(_time, _network, _end, _peerid, _src_sub, _dst_sub, _ts)) + + def private_voice(self, _network, _src_sub, _dst_sub, _ts, _end, _peerid, _data): + # _log = logger.debug + if (_ts not in self.ACTIVE_CALLS) or _end: + _time = time.strftime('%m/%d/%y %H:%M:%S') + _dst_sub = get_info(int_id(_dst_sub)) + _peerid = get_info(int_id(_peerid)) + _src_sub = get_info(int_id(_src_sub)) + if not _end: self.ACTIVE_CALLS.append(_ts) + if _end: self.ACTIVE_CALLS.remove(_ts) + + if _ts: _ts = 2 + else: _ts = 1 + if _end: _end = 'END' + else: _end = 'START' + + print('{} ({}) Call {} Private Voice: \n\tIPSC Source:\t{}\n\tSubscriber:\t{}\n\tDestination:\t{}\n\tTimeslot\t{}' .format(_time, _network, _end, _peerid, _src_sub, _dst_sub, _ts)) + + def group_data(self, _network, _src_sub, _dst_sub, _ts, _end, _peerid, _data): + _dst_sub = get_info(int_id(_dst_sub)) + _peerid = get_info(int_id(_peerid)) + _src_sub = get_info(int_id(_src_sub)) + print('({}) Group Data Packet Received From: {}' .format(_network, _src_sub)) + + def private_data(self, _network, _src_sub, _dst_sub, _ts, _end, _peerid, _data): + _dst_sub = get_info(int_id(_dst_sub)) + _peerid = get_info(int_id(_peerid)) + _src_sub = get_info(int_id(_src_sub)) + print('({}) Private Data Packet Received From: {} To: {}' .format(_network, _src_sub, _dst_sub)) + + +for ipsc_network in NETWORK: + if (NETWORK[ipsc_network]['LOCAL']['ENABLED']): + if NETWORK[ipsc_network]['LOCAL']['AUTH_ENABLED'] == True: + networks[ipsc_network] = logIPSC(ipsc_network) + else: + networks[ipsc_network] = UnauthIPSC(ipsc_network) + reactor.listenUDP(NETWORK[ipsc_network]['LOCAL']['PORT'], networks[ipsc_network]) +reactor.run() \ No newline at end of file