diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 842c902..0000000 --- a/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM python:3.7-slim-stretch - -RUN apt update && \ - apt install -y git && \ - cd /usr/src/ && \ - git clone https://github.com/n0mjs710/dmr_utils3 && \ - cd /usr/src/dmr_utils3 && \ - ./install.sh && \ - rm -rf /var/lib/apt/lists/* && \ - cd /opt && \ - rm -rf /usr/src/dmr_utils3 && \ - git clone https://github.com/n0mjs710/hblink3 -ENV AAA BBBB -RUN cd /opt/hblink3/ && \ - sed -i s/.*python.*//g requirements.txt && \ - pip install --no-cache-dir -r requirements.txt - - -ADD entrypoint /entrypoint - -RUN adduser -u 54000 radio && \ - adduser radio radio && \ - chmod 755 /entrypoint && \ - chown radio:radio /entrypoint && \ - chown radio /opt/hblink3 - -USER radio -EXPOSE 54000 - -ENTRYPOINT [ "/entrypoint" ] diff --git a/app_template.py b/app_template.py deleted file mode 100755 index b919960..0000000 --- a/app_template.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python -# -############################################################################### -# Copyright (C) 2016-2019 Cortney T. Buffington, N0MJS -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -############################################################################### - -# Python modules we need -import sys -from bitarray import bitarray -from time import time -from importlib import import_module - -# Twisted is pretty important, so I keep it separate -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, OPENBRIDGE, systems, hblink_handler, reportFactory, REPORT_OPCODES, mk_aliases -from dmr_utils3.utils import bytes_3, int_id, get_alias -from dmr_utils3 import decode, bptc, const -import config -import log -from const import * - -# Stuff for socket reporting -import pickle -# REMOVE LATER from datetime import datetime -# The module needs logging, but handlers, etc. are controlled by the parent -import logging -logger = logging.getLogger(__name__) - - -# 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-2018 Cortney T. Buffington, N0MJS and the K0USY Group' -__credits__ = 'Colin Durbridge, G4EML, Steve Zingman, N4IRS; Mike Zingman, N4IRR; Jonathan Naylor, G4KLX; Hans Barthen, DL5DI; Torsten Shultze, DG1HT' -__license__ = 'GNU GPLv3' -__maintainer__ = 'Cort Buffington, N0MJS' -__email__ = 'n0mjs@me.com' - -# Module gobal varaibles - - -class OBP(OPENBRIDGE): - - def __init__(self, _name, _config, _report): - OPENBRIDGE.__init__(self, _name, _config, _report) - - - def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): - pass - - -class HBP(HBSYSTEM): - - def __init__(self, _name, _config, _report): - HBSYSTEM.__init__(self, _name, _config, _report) - - def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): - pass - - - -#************************************************ -# MAIN PROGRAM LOOP STARTS HERE -#************************************************ - -if __name__ == '__main__': - - import argparse - import sys - import os - import signal - - # 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='CONFIG_FILE', help='/full/path/to/config.file (usually hblink.cfg)') - parser.add_argument('-l', '--logging', action='store', dest='LOG_LEVEL', help='Override config file logging level.') - cli_args = parser.parse_args() - - # Ensure we have a path for the config file, if one wasn't specified, then use the default (top of file) - if not cli_args.CONFIG_FILE: - cli_args.CONFIG_FILE = os.path.dirname(os.path.abspath(__file__))+'/hblink.cfg' - - # Call the external routine to build the configuration dictionary - CONFIG = config.build_config(cli_args.CONFIG_FILE) - - # Start the system logger - if cli_args.LOG_LEVEL: - CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL - logger = log.config_logging(CONFIG['LOGGER']) - logger.info('\n\nCopyright (c) 2013, 2014, 2015, 2016, 2018\n\tThe Regents of the K0USY Group. All rights reserved.\n') - logger.debug('(GLOBAL) Logging system started, anything from here on gets logged') - - # Set up the signal handler - def sig_handler(_signal, _frame): - logger.info('(GLOBAL) SHUTDOWN: CONFBRIDGE IS TERMINATING WITH SIGNAL %s', str(_signal)) - hblink_handler(_signal, _frame) - logger.info('(GLOBAL) SHUTDOWN: ALL SYSTEM HANDLERS EXECUTED - STOPPING REACTOR') - reactor.stop() - - # Set signal handers so that we can gracefully exit if need be - for sig in [signal.SIGINT, signal.SIGTERM]: - signal.signal(sig, sig_handler) - - # Create the name-number mapping dictionaries - peer_ids, subscriber_ids, talkgroup_ids = mk_aliases(CONFIG) - - # INITIALIZE THE REPORTING LOOP - if CONFIG['REPORTS']['REPORT']: - report_server = config_reports(CONFIG, bridgeReportFactory) - else: - report_server = None - logger.info('(REPORT) TCP Socket reporting not configured') - - # HBlink instance creation - logger.info('(GLOBAL) HBlink \'bridge.py\' -- SYSTEM STARTING...') - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['ENABLED']: - if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE': - systems[system] = OBP(system, CONFIG, report_server) - else: - systems[system] = HBP(system, CONFIG, report_server) - reactor.listenUDP(CONFIG['SYSTEMS'][system]['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['IP']) - logger.debug('(GLOBAL) %s instance created: %s, %s', CONFIG['SYSTEMS'][system]['MODE'], system, systems[system]) - - def loopingErrHandle(failure): - logger.error('(GLOBAL) STOPPING REACTOR TO AVOID MEMORY LEAK: Unhandled error in timed loop.\n %s', failure) - reactor.stop() - - - reactor.run() diff --git a/blank_app.py b/blank_app.py deleted file mode 100755 index b13e29a..0000000 --- a/blank_app.py +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env python -# -############################################################################### -# Copyright (C) 2020 Cortney T. Buffington, N0MJS -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -############################################################################### - -''' -This is a blank application template to build on top of hblink.py. It contains -only the things you need to, essentially, run hblink.py underneath and do nothing -else. The expected behaviour is to override the dmrd_received function from -hblink.py to do somethign meaningful, so that framework is completed, but as -it stands, still does nothing with the DMRD packet. -''' - -# Python modules we need -import sys -from bitarray import bitarray -from time import time -from importlib import import_module -from types import ModuleType - -# Twisted is pretty important, so I keep it separate -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, OPENBRIDGE, systems, hblink_handler, reportFactory, REPORT_OPCODES, config_reports, mk_aliases, acl_check -from dmr_utils3.utils import bytes_3, int_id, get_alias -from dmr_utils3 import decode, bptc, const -import config -import log -import const - -# The module needs logging logging, but handlers, etc. are controlled by the parent -import logging -logger = logging.getLogger(__name__) - - -# Does anybody read this stuff? There's a PEP somewhere that says I should do this. -__author__ = 'Cortney T. Buffington, N0MJS' -__copyright__ = 'Copyright (c) 2020 Cortney T. Buffington' -__credits__ = 'Colin Durbridge, G4EML, Steve Zingman, N4IRS; Mike Zingman, N4IRR; Jonathan Naylor, G4KLX; Hans Barthen, DL5DI; Torsten Shultze, DG1HT' -__license__ = 'GNU GPLv3' -__maintainer__ = 'Cort Buffington, N0MJS' -__email__ = 'n0mjs@me.com' -__status__ = 'pre-alpha' - -# Module gobal varaibles - - -class blankSYSTEM(HBSYSTEM): - - def __init__(self, _name, _config, _report): - HBSYSTEM.__init__(self, _name, _config, _report) - - def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): - pass - - -#************************************************ -# MAIN PROGRAM LOOP STARTS HERE -#************************************************ - -if __name__ == '__main__': - import argparse - import sys - import os - import signal - from dmr_utils3.utils import try_download, mk_id_dict - - # 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='CONFIG_FILE', help='/full/path/to/config.file (usually hblink.cfg)') - parser.add_argument('-l', '--logging', action='store', dest='LOG_LEVEL', help='Override config file logging level.') - cli_args = parser.parse_args() - - # Ensure we have a path for the config file, if one wasn't specified, then use the default (top of file) - if not cli_args.CONFIG_FILE: - cli_args.CONFIG_FILE = os.path.dirname(os.path.abspath(__file__))+'/hblink.cfg' - - # Call the external routine to build the configuration dictionary - CONFIG = config.build_config(cli_args.CONFIG_FILE) - - # Start the system logger - if cli_args.LOG_LEVEL: - CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL - logger = log.config_logging(CONFIG['LOGGER']) - logger.info('\n\nCopyright (c) 2013, 2014, 2015, 2016, 2018, 2019\n\tThe Regents of the K0USY Group. All rights reserved.\n') - logger.debug('Logging system started, anything from here on gets logged') - - # Set up the signal handler - def sig_handler(_signal, _frame): - logger.info('SHUTDOWN: >>>BLANK APP<<< IS TERMINATING WITH SIGNAL %s', str(_signal)) - hblink_handler(_signal, _frame) - logger.info('SHUTDOWN: ALL SYSTEM HANDLERS EXECUTED - STOPPING REACTOR') - reactor.stop() - - # Set signal handers so that we can gracefully exit if need be - for sig in [signal.SIGTERM, signal.SIGINT]: - signal.signal(sig, sig_handler) - - # Create the name-number mapping dictionaries - peer_ids, subscriber_ids, talkgroup_ids = mk_aliases(CONFIG) - - - # INITIALIZE THE REPORTING LOOP - if CONFIG['REPORTS']['REPORT']: - report_server = config_reports(CONFIG, reportFactory) - else: - report_server = None - logger.info('(REPORT) TCP Socket reporting not configured') - - # HBlink instance creation - logger.info('HBlink \'blank_app.py\' -- SYSTEM STARTING...') - for system in CONFIG['SYSTEMS']: - if CONFIG['SYSTEMS'][system]['ENABLED']: - if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE': - systems[system] = OPENBRIDGE(system, CONFIG, report_server) - else: - systems[system] = HBSYSTEM(system, CONFIG, 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]) - - reactor.run() diff --git a/config.py b/config.py index f86628c..c5daed2 100755 --- a/config.py +++ b/config.py @@ -199,52 +199,6 @@ def build_config(_config_file): 'LAST_PING_ACK_TIME': 0, }}) - if config.get(section, 'MODE') == 'XLXPEER': - CONFIG['SYSTEMS'].update({section: { - 'MODE': config.get(section, 'MODE'), - 'ENABLED': config.getboolean(section, 'ENABLED'), - 'LOOSE': config.getboolean(section, 'LOOSE'), - 'SOCK_ADDR': (gethostbyname(config.get(section, 'IP')), config.getint(section, 'PORT')), - 'IP': gethostbyname(config.get(section, 'IP')), - 'PORT': config.getint(section, 'PORT'), - 'MASTER_SOCKADDR': (gethostbyname(config.get(section, 'MASTER_IP')), config.getint(section, 'MASTER_PORT')), - 'MASTER_IP': gethostbyname(config.get(section, 'MASTER_IP')), - 'MASTER_PORT': config.getint(section, 'MASTER_PORT'), - 'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE'), 'utf-8'), - 'CALLSIGN': bytes(config.get(section, 'CALLSIGN').ljust(8)[:8], 'utf-8'), - 'RADIO_ID': config.getint(section, 'RADIO_ID').to_bytes(4, 'big'), - 'RX_FREQ': bytes(config.get(section, 'RX_FREQ').ljust(9)[:9], 'utf-8'), - 'TX_FREQ': bytes(config.get(section, 'TX_FREQ').ljust(9)[:9], 'utf-8'), - 'TX_POWER': bytes(config.get(section, 'TX_POWER').rjust(2,'0'), 'utf-8'), - 'COLORCODE': bytes(config.get(section, 'COLORCODE').rjust(2,'0'), 'utf-8'), - 'LATITUDE': bytes(config.get(section, 'LATITUDE').ljust(8)[:8], 'utf-8'), - 'LONGITUDE': bytes(config.get(section, 'LONGITUDE').ljust(9)[:9], 'utf-8'), - 'HEIGHT': bytes(config.get(section, 'HEIGHT').rjust(3,'0'), 'utf-8'), - 'LOCATION': bytes(config.get(section, 'LOCATION').ljust(20)[:20], 'utf-8'), - 'DESCRIPTION': bytes(config.get(section, 'DESCRIPTION').ljust(19)[:19], 'utf-8'), - 'SLOTS': bytes(config.get(section, 'SLOTS'), 'utf-8'), - 'URL': bytes(config.get(section, 'URL').ljust(124)[:124], 'utf-8'), - 'SOFTWARE_ID': bytes(config.get(section, 'SOFTWARE_ID').ljust(40)[:40], 'utf-8'), - 'PACKAGE_ID': bytes(config.get(section, 'PACKAGE_ID').ljust(40)[:40], 'utf-8'), - 'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME'), - 'XLXMODULE': config.getint(section, 'XLXMODULE'), - 'OPTIONS': '', - 'USE_ACL': config.getboolean(section, 'USE_ACL'), - 'SUB_ACL': config.get(section, 'SUB_ACL'), - 'TG1_ACL': config.get(section, 'TGID_TS1_ACL'), - 'TG2_ACL': config.get(section, 'TGID_TS2_ACL') - }}) - CONFIG['SYSTEMS'][section].update({'XLXSTATS': { - 'CONNECTION': 'NO', # NO, RTPL_SENT, AUTHENTICATED, CONFIG-SENT, YES - 'CONNECTED': None, - 'PINGS_SENT': 0, - 'PINGS_ACKD': 0, - 'NUM_OUTSTANDING': 0, - 'PING_OUTSTANDING': False, - 'LAST_PING_TX_TIME': 0, - 'LAST_PING_ACK_TIME': 0, - }}) - elif config.get(section, 'MODE') == 'MASTER': CONFIG['SYSTEMS'].update({section: { 'MODE': config.get(section, 'MODE'), diff --git a/entrypoint b/entrypoint deleted file mode 100755 index 422f0f3..0000000 --- a/entrypoint +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -if [ -z "$GIT_REPO" ]; then - mkdir -p /var/tmp/config - cd /var/tmp/config - git clone https://${GIT_USER}:${GIT_PASSWORD}@${GIT_REPO} - - DIR=$(echo ${GIT_REPO}| sed s/.git$//g | sed s#^.*/##g) - - cp -a /var/tmp/config/${DIR}/*cfg /opt/hblink3/ - cp -a /var/tmp/config/${DIR}/*csv /opt/hblink3/ - cp -a /var/tmp/config/${DIR}/*json /opt/hblink3/ -else - cp -a /opt/config/*cfg /opt/hblink3/ - cp -a /opt/config/*csv /opt/hblink3/ - cp -a /opt/config/*json /opt/hblink3/ -fi -cd /opt/hblink3 -python /opt/hblink3/hblink.py -c hblink.cfg diff --git a/hblink-SAMPLE.cfg b/hblink-SAMPLE.cfg index a3b616c..cf56295 100755 --- a/hblink-SAMPLE.cfg +++ b/hblink-SAMPLE.cfg @@ -206,36 +206,4 @@ OPTIONS: USE_ACL: True SUB_ACL: DENY:1 TGID_TS1_ACL: PERMIT:ALL -TGID_TS2_ACL: PERMIT:ALL - -[XLX-1] -MODE: XLXPEER -ENABLED: True -LOOSE: True -EXPORT_AMBE: False -IP: -PORT: 54002 -MASTER_IP: 172.16.1.1 -MASTER_PORT: 62030 -PASSPHRASE: passw0rd -CALLSIGN: W1ABC -RADIO_ID: 312000 -RX_FREQ: 449000000 -TX_FREQ: 444000000 -TX_POWER: 25 -COLORCODE: 1 -SLOTS: 1 -LATITUDE: 38.0000 -LONGITUDE: -095.0000 -HEIGHT: 75 -LOCATION: Anywhere, USA -DESCRIPTION: This is a cool repeater -URL: www.w1abc.org -SOFTWARE_ID: 20170620 -PACKAGE_ID: MMDVM_HBlink -GROUP_HANGTIME: 5 -XLXMODULE: 4004 -USE_ACL: True -SUB_ACL: DENY:1 -TGID_TS1_ACL: PERMIT:ALL -TGID_TS2_ACL: PERMIT:ALL +TGID_TS2_ACL: PERMIT:ALL \ No newline at end of file diff --git a/hblink.py b/hblink.py index 83b67ad..bbcff98 100755 --- a/hblink.py +++ b/hblink.py @@ -223,13 +223,6 @@ class HBSYSTEM(DatagramProtocol): self.datagramReceived = self.peer_datagramReceived self.dereg = self.peer_dereg - elif self._config['MODE'] == 'XLXPEER': - self._stats = self._config['XLXSTATS'] - self.send_system = self.send_master - self.maintenance_loop = self.peer_maintenance_loop - self.datagramReceived = self.peer_datagramReceived - self.dereg = self.peer_dereg - def startProtocol(self): # Set up periodic loop for tracking pings from peers. Run every 'PING_TIME' seconds self._system_maintenance = task.LoopingCall(self.maintenance_loop) @@ -289,29 +282,6 @@ class HBSYSTEM(DatagramProtocol): # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! # logger.debug('(%s) TX Packet to %s:%s -- %s', self._system, self._config['MASTER_IP'], self._config['MASTER_PORT'], ahex(_packet)) - def send_xlxmaster(self, radio, xlx, mastersock): - radio3 = int.from_bytes(radio, 'big').to_bytes(3, 'big') - radio4 = int.from_bytes(radio, 'big').to_bytes(4, 'big') - xlx3 = xlx.to_bytes(3, 'big') - streamid = randint(0,255).to_bytes(1, 'big')+randint(0,255).to_bytes(1, 'big')+randint(0,255).to_bytes(1, 'big')+randint(0,255).to_bytes(1, 'big') - # Wait for .5 secs for the XLX to log us in - for packetnr in range(5): - if packetnr < 3: - # First 3 packets, voice start, stream type e1 - strmtype = 225 - payload = bytearray.fromhex('4f2e00b501ae3a001c40a0c1cc7dff57d75df5d5065026f82880bd616f13f185890000') - else: - # Last 2 packets, voice end, stream type e2 - strmtype = 226 - payload = bytearray.fromhex('4f410061011e3a781c30a061ccbdff57d75df5d2534425c02fe0b1216713e885ba0000') - packetnr1 = packetnr.to_bytes(1, 'big') - strmtype1 = strmtype.to_bytes(1, 'big') - _packet = b''.join([DMRD, packetnr1, radio3, xlx3, radio4, strmtype1, streamid, payload]) - self.transport.write(_packet, mastersock) - # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! - #logger.debug('(%s) XLX Module Change Packet: %s', self._system, ahex(_packet)) - return - def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pass @@ -648,11 +618,7 @@ class HBSYSTEM(DatagramProtocol): self._stats['CONNECTION'] = 'YES' self._stats['CONNECTED'] = time() logger.info('(%s) Connection to Master Completed', self._system) - # If we are an XLX, send the XLX module request here. - if self._config['MODE'] == 'XLXPEER': - self.send_xlxmaster(self._config['RADIO_ID'], int(4000), self._config['MASTER_SOCKADDR']) - self.send_xlxmaster(self._config['RADIO_ID'], self._config['XLXMODULE'], self._config['MASTER_SOCKADDR']) - logger.info('(%s) Sending XLX Module request', self._system) + else: self._stats['CONNECTION'] = 'NO' logger.error('(%s) Master ACK Contained wrong ID - Connection Reset', self._system)