mirror of
https://github.com/craigerl/aprsd.git
synced 2025-04-19 09:49:01 -04:00
Updated APRSIS driver
This patch adds an override to _connect to set some more socket keepalive options.
This commit is contained in:
parent
3b57e7597d
commit
1606585d41
@ -1,6 +1,7 @@
|
||||
import datetime
|
||||
import logging
|
||||
import select
|
||||
import socket
|
||||
import threading
|
||||
|
||||
import aprslib
|
||||
@ -18,7 +19,7 @@ from aprslib.exceptions import (
|
||||
import aprsd
|
||||
from aprsd.packets import core
|
||||
|
||||
LOG = logging.getLogger("APRSD")
|
||||
LOG = logging.getLogger('APRSD')
|
||||
|
||||
|
||||
class Aprsdis(aprslib.IS):
|
||||
@ -31,7 +32,7 @@ class Aprsdis(aprslib.IS):
|
||||
aprsd_keepalive = datetime.datetime.now()
|
||||
|
||||
# Which server we are connected to?
|
||||
server_string = "None"
|
||||
server_string = 'None'
|
||||
|
||||
# timeout in seconds
|
||||
select_timeout = 1
|
||||
@ -39,10 +40,10 @@ class Aprsdis(aprslib.IS):
|
||||
|
||||
def stop(self):
|
||||
self.thread_stop = True
|
||||
LOG.warning("Shutdown Aprsdis client.")
|
||||
LOG.warning('Shutdown Aprsdis client.')
|
||||
|
||||
def close(self):
|
||||
LOG.warning("Closing Aprsdis client.")
|
||||
LOG.warning('Closing Aprsdis client.')
|
||||
super().close()
|
||||
|
||||
@wrapt.synchronized(lock)
|
||||
@ -54,6 +55,57 @@ class Aprsdis(aprslib.IS):
|
||||
"""If the connection is alive or not."""
|
||||
return self._connected
|
||||
|
||||
def _connect(self):
|
||||
"""
|
||||
Attemps connection to the server
|
||||
"""
|
||||
|
||||
self.logger.info(
|
||||
'Attempting connection to %s:%s', self.server[0], self.server[1]
|
||||
)
|
||||
|
||||
try:
|
||||
self._open_socket()
|
||||
|
||||
peer = self.sock.getpeername()
|
||||
|
||||
self.logger.info('Connected to %s', str(peer))
|
||||
|
||||
# 5 second timeout to receive server banner
|
||||
self.sock.setblocking(1)
|
||||
self.sock.settimeout(5)
|
||||
|
||||
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
# MACOS doesn't have TCP_KEEPIDLE
|
||||
if hasattr(socket, 'TCP_KEEPIDLE'):
|
||||
self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1)
|
||||
self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 3)
|
||||
self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5)
|
||||
|
||||
banner = self.sock.recv(512)
|
||||
if is_py3:
|
||||
banner = banner.decode('latin-1')
|
||||
|
||||
if banner[0] == '#':
|
||||
self.logger.debug('Banner: %s', banner.rstrip())
|
||||
else:
|
||||
raise ConnectionError('invalid banner from server')
|
||||
|
||||
except ConnectionError as e:
|
||||
self.logger.error(str(e))
|
||||
self.close()
|
||||
raise
|
||||
except (socket.error, socket.timeout) as e:
|
||||
self.close()
|
||||
|
||||
self.logger.error('Socket error: %s' % str(e))
|
||||
if str(e) == 'timed out':
|
||||
raise ConnectionError('no banner from server') from e
|
||||
else:
|
||||
raise ConnectionError(e) from e
|
||||
|
||||
self._connected = True
|
||||
|
||||
def _socket_readlines(self, blocking=False):
|
||||
"""
|
||||
Generator for complete lines, received from the server
|
||||
@ -61,12 +113,12 @@ class Aprsdis(aprslib.IS):
|
||||
try:
|
||||
self.sock.setblocking(0)
|
||||
except OSError as e:
|
||||
self.logger.error(f"socket error when setblocking(0): {str(e)}")
|
||||
raise aprslib.ConnectionDrop("connection dropped")
|
||||
self.logger.error(f'socket error when setblocking(0): {str(e)}')
|
||||
raise aprslib.ConnectionDrop('connection dropped') from e
|
||||
|
||||
while not self.thread_stop:
|
||||
short_buf = b""
|
||||
newline = b"\r\n"
|
||||
short_buf = b''
|
||||
newline = b'\r\n'
|
||||
|
||||
# set a select timeout, so we get a chance to exit
|
||||
# when user hits CTRL-C
|
||||
@ -91,11 +143,11 @@ class Aprsdis(aprslib.IS):
|
||||
# We could just not be blocking, so empty is expected
|
||||
continue
|
||||
else:
|
||||
self.logger.error("socket.recv(): returned empty")
|
||||
raise aprslib.ConnectionDrop("connection dropped")
|
||||
self.logger.error('socket.recv(): returned empty')
|
||||
raise aprslib.ConnectionDrop('connection dropped')
|
||||
except OSError as e:
|
||||
# self.logger.error("socket error on recv(): %s" % str(e))
|
||||
if "Resource temporarily unavailable" in str(e):
|
||||
if 'Resource temporarily unavailable' in str(e):
|
||||
if not blocking:
|
||||
if len(self.buf) == 0:
|
||||
break
|
||||
@ -111,22 +163,22 @@ class Aprsdis(aprslib.IS):
|
||||
"""
|
||||
Sends login string to server
|
||||
"""
|
||||
login_str = "user {0} pass {1} vers github.com/craigerl/aprsd {3}{2}\r\n"
|
||||
login_str = 'user {0} pass {1} vers Python-APRSD {3}{2}\r\n'
|
||||
login_str = login_str.format(
|
||||
self.callsign,
|
||||
self.passwd,
|
||||
(" filter " + self.filter) if self.filter != "" else "",
|
||||
(' filter ' + self.filter) if self.filter != '' else '',
|
||||
aprsd.__version__,
|
||||
)
|
||||
|
||||
self.logger.debug("Sending login information")
|
||||
self.logger.debug('Sending login information')
|
||||
|
||||
try:
|
||||
self._sendall(login_str)
|
||||
self.sock.settimeout(5)
|
||||
test = self.sock.recv(len(login_str) + 100)
|
||||
if is_py3:
|
||||
test = test.decode("latin-1")
|
||||
test = test.decode('latin-1')
|
||||
test = test.rstrip()
|
||||
|
||||
self.logger.debug("Server: '%s'", test)
|
||||
@ -134,26 +186,26 @@ class Aprsdis(aprslib.IS):
|
||||
if not test:
|
||||
raise LoginError(f"Server Response Empty: '{test}'")
|
||||
|
||||
_, _, callsign, status, e = test.split(" ", 4)
|
||||
s = e.split(",")
|
||||
_, _, callsign, status, e = test.split(' ', 4)
|
||||
s = e.split(',')
|
||||
if len(s):
|
||||
server_string = s[0].replace("server ", "")
|
||||
server_string = s[0].replace('server ', '')
|
||||
else:
|
||||
server_string = e.replace("server ", "")
|
||||
server_string = e.replace('server ', '')
|
||||
|
||||
if callsign == "":
|
||||
raise LoginError("Server responded with empty callsign???")
|
||||
if callsign == '':
|
||||
raise LoginError('Server responded with empty callsign???')
|
||||
if callsign != self.callsign:
|
||||
raise LoginError(f"Server: {test}")
|
||||
if status != "verified," and self.passwd != "-1":
|
||||
raise LoginError("Password is incorrect")
|
||||
raise LoginError(f'Server: {test}')
|
||||
if status != 'verified,' and self.passwd != '-1':
|
||||
raise LoginError('Password is incorrect')
|
||||
|
||||
if self.passwd == "-1":
|
||||
self.logger.info("Login successful (receive only)")
|
||||
if self.passwd == '-1':
|
||||
self.logger.info('Login successful (receive only)')
|
||||
else:
|
||||
self.logger.info("Login successful")
|
||||
self.logger.info('Login successful')
|
||||
|
||||
self.logger.info(f"Connected to {server_string}")
|
||||
self.logger.info(f'Connected to {server_string}')
|
||||
self.server_string = server_string
|
||||
|
||||
except LoginError as e:
|
||||
@ -164,7 +216,7 @@ class Aprsdis(aprslib.IS):
|
||||
self.close()
|
||||
self.logger.error(f"Failed to login '{e}'")
|
||||
self.logger.exception(e)
|
||||
raise LoginError("Failed to login")
|
||||
raise LoginError('Failed to login') from e
|
||||
|
||||
def consumer(self, callback, blocking=True, immortal=False, raw=False):
|
||||
"""
|
||||
@ -180,21 +232,21 @@ class Aprsdis(aprslib.IS):
|
||||
"""
|
||||
|
||||
if not self._connected:
|
||||
raise ConnectionError("not connected to a server")
|
||||
raise ConnectionError('not connected to a server')
|
||||
|
||||
line = b""
|
||||
line = b''
|
||||
|
||||
while True and not self.thread_stop:
|
||||
try:
|
||||
for line in self._socket_readlines(blocking):
|
||||
if line[0:1] != b"#":
|
||||
if line[0:1] != b'#':
|
||||
self.aprsd_keepalive = datetime.datetime.now()
|
||||
if raw:
|
||||
callback(line)
|
||||
else:
|
||||
callback(self._parse(line))
|
||||
else:
|
||||
self.logger.debug("Server: %s", line.decode("utf8"))
|
||||
self.logger.debug('Server: %s', line.decode('utf8'))
|
||||
self.aprsd_keepalive = datetime.datetime.now()
|
||||
except ParseError as exp:
|
||||
self.logger.log(
|
||||
@ -211,7 +263,7 @@ class Aprsdis(aprslib.IS):
|
||||
exp.packet,
|
||||
)
|
||||
except LoginError as exp:
|
||||
self.logger.error("%s: %s", exp.__class__.__name__, exp)
|
||||
self.logger.error('%s: %s', exp.__class__.__name__, exp)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except (ConnectionDrop, ConnectionError):
|
||||
@ -227,7 +279,7 @@ class Aprsdis(aprslib.IS):
|
||||
except StopIteration:
|
||||
break
|
||||
except Exception:
|
||||
self.logger.error("APRS Packet: %s", line)
|
||||
self.logger.error('APRS Packet: %s', line)
|
||||
raise
|
||||
|
||||
if not blocking:
|
||||
|
Loading…
Reference in New Issue
Block a user