diff --git a/src/__init__.py b/src/__init__.py index c094e1fb..9fa6057e 100755 --- a/src/__init__.py +++ b/src/__init__.py @@ -97,10 +97,11 @@ if config.get('advanced.security_auditing', True): pass - - def onionr_main(): - """Onionr entrypoint, start command processor""" + """Onionr entrypoint, start command processor + + Entrypoint for daemon is commands/daemonlaunch/__init__.py + """ parser.register() diff --git a/src/gossip/client/streamblocks.py b/src/gossip/client/streamblocks.py index 84ce88a6..c349c645 100644 --- a/src/gossip/client/streamblocks.py +++ b/src/gossip/client/streamblocks.py @@ -101,8 +101,9 @@ def stream_from_peers(): raise # Tell them to keep streaming sock.sendall(int(1).to_bytes(1, 'big')) - except BrokenPipeError: - pass + except (BrokenPipeError, TimeoutError) as e: + logger.info(f"{e} when streaming peers", terminal=True) + logger.debug(traceback.format_exc()) except Exception: logger.warn(traceback.format_exc(), terminal=True) finally: diff --git a/src/onionrcommands/daemonlaunch/__init__.py b/src/onionrcommands/daemonlaunch/__init__.py index 2dba869d..acb6728f 100755 --- a/src/onionrcommands/daemonlaunch/__init__.py +++ b/src/onionrcommands/daemonlaunch/__init__.py @@ -117,6 +117,7 @@ def daemon(): try: apiservers.private_api.start() + events.event('shutdown', threaded=False) except KeyboardInterrupt: pass diff --git a/static-data/default-plugins/tor/bootstrap.py b/static-data/default-plugins/tor/bootstrap.py index 225363b0..0c69b184 100644 --- a/static-data/default-plugins/tor/bootstrap.py +++ b/static-data/default-plugins/tor/bootstrap.py @@ -1,26 +1,55 @@ +import shelve from threading import Thread from time import sleep import os +import traceback +from typing import Callable from gossip.peer import Peer from gossip.peerset import gossip_peer_set +from utils.identifyhome import identify_home import logger import config from getsocks import get_socks from torpeer import TorPeer -from torfilepaths import control_socket +from torfilepaths import control_socket, peer_database_file bootstrap_file = f'{os.path.dirname(os.path.realpath(__file__))}/bootstrap.txt' +def load_existing_peers(callback: Callable): + """Load peers saved to disk""" + peer_address: str = '' + + # the peers here are saved on clean shutdown + with shelve.open(peer_database_file, 'r') as tor_peer_db: + peer_address: str = tor_peer_db.nextkey() + while peer_address: + Thread( + target=callback, + args=[tor_peer_db[peer_address]], + name=f'{peer_address} connection attempt', + daemon=True).start() + + def on_bootstrap(api, data): + callback_func = data['callback'] + try: - with open(bootstrap_file, 'r') as bootstrap_file_obj: - bootstrap_nodes = set(bootstrap_file_obj.read().split(',')) + load_existing_peers(callback_func) except FileNotFoundError: - bootstrap_nodes = set() + try: + with open(bootstrap_file, 'r') as bootstrap_file_obj: + bootstrap_nodes = set(bootstrap_file_obj.read().split(',')) + except FileNotFoundError: + bootstrap_nodes = set() + except Exception as e: + logger.warn(traceback.format_exc()) + return + else: + return while not os.path.exists(control_socket): sleep(0.1) @@ -39,7 +68,7 @@ def on_bootstrap(api, data): # Tell the gossip logic that this peer is ready to connect # it will add it to data['peer_set'] if it responds to ping Thread( - target=data['callback'], + target=callback_func, args=[TorPeer(socks_address, socks_port, address)], daemon=True).start() diff --git a/static-data/default-plugins/tor/bootstrap.txt b/static-data/default-plugins/tor/bootstrap.txt index e69de29b..771848ab 100644 --- a/static-data/default-plugins/tor/bootstrap.txt +++ b/static-data/default-plugins/tor/bootstrap.txt @@ -0,0 +1 @@ +b3u6g7syd6ddicwoxe7ydelqnldyr6g5skvvmjzgh6duwjk6jhv2ixqd \ No newline at end of file diff --git a/static-data/default-plugins/tor/main.py b/static-data/default-plugins/tor/main.py index bba3a47e..04206b18 100644 --- a/static-data/default-plugins/tor/main.py +++ b/static-data/default-plugins/tor/main.py @@ -30,6 +30,7 @@ from torfilepaths import control_socket from bootstrap import on_bootstrap from announce import on_announce_rec +from shutdown import on_shutdown_event """ This program is free software: you can redistribute it and/or modify @@ -92,7 +93,8 @@ def on_gossip_start(api, data: Set[Peer] = None): try: add_onion_resp = controller.create_ephemeral_hidden_service( {'80': f'unix:{gossip_server_socket_file}'}, - key_content=key, key_type='ED25519-V3', detached=True, await_publication=True) + key_content=key, key_type='ED25519-V3', + detached=True, await_publication=True) except stem.ProtocolError: logger.error( "Could not start Tor transport. Try restarting Onionr", diff --git a/static-data/default-plugins/tor/shutdown.py b/static-data/default-plugins/tor/shutdown.py new file mode 100644 index 00000000..416092f1 --- /dev/null +++ b/static-data/default-plugins/tor/shutdown.py @@ -0,0 +1,12 @@ +import shelve +from gossip.peerset import gossip_peer_set + +from torpeer import TorPeer +from torfilepaths import peer_database_file + + +def on_shutdown_event(api, data=None): + with shelve.open(peer_database_file, 'c') as db: + for peer in gossip_peer_set: + if isinstance(peer, TorPeer): + db[peer.onion_address] = peer diff --git a/static-data/default-plugins/tor/torfilepaths.py b/static-data/default-plugins/tor/torfilepaths.py index ffb31306..0630a894 100644 --- a/static-data/default-plugins/tor/torfilepaths.py +++ b/static-data/default-plugins/tor/torfilepaths.py @@ -1,3 +1,4 @@ from utils.identifyhome import identify_home control_socket = f'{identify_home()}/torcontrol.sock' -tor_data_dir = f'{identify_home()}/tordata' \ No newline at end of file +tor_data_dir = f'{identify_home()}/tordata' +peer_database_file = f'{identify_home()}/tor-peers'