diff --git a/src/gossip/client/announce.py b/src/gossip/client/announce.py index c21c6c3c..1d02b0ad 100644 --- a/src/gossip/client/announce.py +++ b/src/gossip/client/announce.py @@ -20,8 +20,8 @@ def do_announce(): except AttributeError: pass sock = announce_peer.get_socket(12) - sock.sendall( - command_to_byte(GossipCommands.ANNOUNCE) + our_transport_address) + sock.sendall(command_to_byte(GossipCommands.ANNOUNCE)) + sock.sendall(our_transport_address) if int.from_bytes(sock.recv(1), 'big') != 1: logger.warn( f"Could not announce with {announce_peer.transport_address}") diff --git a/static-data/default-plugins/unixtransport/announce.py b/static-data/default-plugins/unixtransport/announce.py new file mode 100644 index 00000000..951d6271 --- /dev/null +++ b/static-data/default-plugins/unixtransport/announce.py @@ -0,0 +1,25 @@ +import config +import logger +from gossip.server import gossip_server_socket_file + +from unixpeer import UnixPeer + + +def on_announce_rec(api, data=None): + + announced: str = data['address'] + try: + announced = announced.decode('utf-8') + except AttributeError: + pass + announced = announced.strip() + + if announced == gossip_server_socket_file: + logger.warn( + "Received announcement for our unix node, which shouldn't happen", + terminal=True) + return + + logger.info(f"Peer {announced} announced to us.", terminal=True) + + data['callback'](UnixPeer(announced)) diff --git a/static-data/default-plugins/unixtransport/bootstrap.py b/static-data/default-plugins/unixtransport/bootstrap.py new file mode 100644 index 00000000..1305998e --- /dev/null +++ b/static-data/default-plugins/unixtransport/bootstrap.py @@ -0,0 +1,68 @@ +import shelve +from threading import Thread +from time import sleep +import os +import dbm +import traceback +from typing import Callable + +from gossip.server import gossip_server_socket_file +from gossip.peer import Peer +from gossip.peerset import gossip_peer_set +from utils.identifyhome import identify_home +import logger +import config + +from unixpeer import UnixPeer +from unixfilepaths import 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 unix_peer_db: + peer_address: str = unix_peer_db.nextkey() + while peer_address: + Thread( + target=callback, + args=[unix_peer_db[peer_address]], + name=f'{peer_address} connection attempt', + daemon=True).start() + + +def on_bootstrap(api, data): + + callback_func = data['callback'] + + try: + load_existing_peers(callback_func) + except dbm.error: + 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(), terminal=True) + return + else: + return + + while not os.path.exists(gossip_server_socket_file): + sleep(0.1) + + for address in bootstrap_nodes: + if address == gossip_server_socket_file or not address: + continue + + # 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=callback_func, + args=[UnixPeer(address)], + daemon=True).start() + diff --git a/static-data/default-plugins/unixtransport/bootstrap.txt b/static-data/default-plugins/unixtransport/bootstrap.txt new file mode 100644 index 00000000..9f935d1d --- /dev/null +++ b/static-data/default-plugins/unixtransport/bootstrap.txt @@ -0,0 +1 @@ +/dev/shm/onionr655223043/gossip-server.sock \ No newline at end of file diff --git a/static-data/default-plugins/unixtransport/main.py b/static-data/default-plugins/unixtransport/main.py new file mode 100644 index 00000000..a363a4d5 --- /dev/null +++ b/static-data/default-plugins/unixtransport/main.py @@ -0,0 +1,71 @@ +"""Onionr - Private P2P Communication. + +Unix transport plugin. Intended for testing Onionr networks using IPC +""" +import sys +import os +import locale +from time import sleep +import traceback +from typing import Set, TYPE_CHECKING +from threading import Thread + +import stem +from stem.control import Controller + +import logger +from utils import readstatic +import config +from filepaths import gossip_server_socket_file + +from gossip.peer import Peer + +locale.setlocale(locale.LC_ALL, '') +sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) +# import after path insert +from unixpeer import UnixPeer + +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 +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, see . +""" + + +plugin_name = 'unixtransport' +PLUGIN_VERSION = '0.0.0' + + + + +def on_init(api, data=None): + logger.info( + f"Unix Transport Plugin v{PLUGIN_VERSION} enabled", terminal=True) + logger.info( + f"Peers can connect to {gossip_server_socket_file}", terminal=True) + + +def on_get_our_transport(api, data=None): + callback_func = data['callback'] + for_peer = data['peer'] + if data['peer'].__class__ == UnixPeer: + callback_func(for_peer, gossip_server_socket_file) + + +def on_gossip_start(api, data: Set[Peer] = None): + # We don't do gossip logic + return + diff --git a/static-data/default-plugins/unixtransport/unixfilepaths.py b/static-data/default-plugins/unixtransport/unixfilepaths.py new file mode 100644 index 00000000..2430dc44 --- /dev/null +++ b/static-data/default-plugins/unixtransport/unixfilepaths.py @@ -0,0 +1,2 @@ +from utils.identifyhome import identify_home +peer_database_file = f'{identify_home()}/unix-peers' \ No newline at end of file diff --git a/static-data/default-plugins/unixtransport/unixpeer.py b/static-data/default-plugins/unixtransport/unixpeer.py new file mode 100644 index 00000000..d679abe8 --- /dev/null +++ b/static-data/default-plugins/unixtransport/unixpeer.py @@ -0,0 +1,28 @@ +from os.path import exists +from socket import AF_UNIX, SOCK_STREAM, socket + +class UnixPeer: + + def __init__(self, socket_file): + + if not exists(socket_file): + raise FileExistsError("No such file " + socket_file) + + self.transport_address = socket_file + + + def get_socket(self, connect_timeout) -> socket: + + s = socket(AF_UNIX, SOCK_STREAM) + #s.settimeout(connect_timeout) + s.connect(self.transport_address) + return s + + def __hash__(self): + return hash(self.transport_address) + + def __eq__(self, other): + try: + return self.transport_address == other.transport_address + except AttributeError: + return False