Reference client for Bitmessage: a P2P encrypted decentralised communication protocol:
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
4.4 KiB

# pylint: disable=protected-access
import logging
import socket
import time
import asyncore_pollchoose as asyncore
from advanceddispatcher import AdvancedDispatcher
from bmconfigparser import BMConfigParser
from node import Peer
logger = logging.getLogger('default')
class ProxyError(Exception):
"""Base proxy exception class"""
errorCodes = ("Unknown error",)
def __init__(self, code=-1):
self.code = code
self.message = self.errorCodes[code]
except IndexError:
self.message = self.errorCodes[-1]
super(ProxyError, self).__init__(self.message)
class GeneralProxyError(ProxyError):
"""General proxy error class (not specfic to an implementation)"""
errorCodes = (
"Invalid data",
"Not connected",
"Not available",
"Bad proxy type",
"Bad input",
"Timed out",
"Network unreachable",
"Connection refused",
"Host unreachable"
class Proxy(AdvancedDispatcher):
"""Base proxy class"""
# these are global, and if you change config during runtime,
# all active/new instances should change too
_proxy = ("", 9050)
_auth = None
_onion_proxy = None
_onion_auth = None
_remote_dns = True
def proxy(self):
"""Return proxy IP and port"""
return self.__class__._proxy
def proxy(self, address):
"""Set proxy IP and port"""
if (not isinstance(address, tuple) or len(address) < 2 or
not isinstance(address[0], str) or
not isinstance(address[1], int)):
raise ValueError
self.__class__._proxy = address
def auth(self):
"""Return proxy authentication settings"""
return self.__class__._auth
def auth(self, authTuple):
"""Set proxy authentication (username and password)"""
self.__class__._auth = authTuple
def onion_proxy(self):
Return separate proxy IP and port for use only with onion
addresses. Untested.
return self.__class__._onion_proxy
def onion_proxy(self, address):
"""Set onion proxy address"""
if address is not None and (
not isinstance(address, tuple) or len(address) < 2
or not isinstance(address[0], str)
or not isinstance(address[1], int)
raise ValueError
self.__class__._onion_proxy = address
def onion_auth(self):
"""Return proxy authentication settings for onion hosts only"""
return self.__class__._onion_auth
def onion_auth(self, authTuple):
"""Set proxy authentication for onion hosts only. Untested."""
self.__class__._onion_auth = authTuple
def __init__(self, address):
if not isinstance(address, Peer):
raise ValueError
self.destination = address
self.isOutbound = True
self.fullyEstablished = False
self.connectedAt = 0
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
if BMConfigParser().safeGetBoolean(
"bitmessagesettings", "socksauthentication"):
self.auth = (
"bitmessagesettings", "socksusername"),
"bitmessagesettings", "sockspassword")
self.auth = None
if".onion") and self.onion_proxy else
def handle_connect(self):
"""Handle connection event (to the proxy)"""
except socket.error as e:
if e.errno in asyncore._DISCONNECTED:
"%s:%i: Connection failed: %s",, self.destination.port, e)
def state_proxy_handshake_done(self):
"""Handshake is complete at this point"""
# pylint: disable=attribute-defined-outside-init
self.connectedAt = time.time()
return False