2015-07-12 20:36:46 +02:00
|
|
|
import socket
|
|
|
|
import time
|
|
|
|
|
|
|
|
import gevent
|
|
|
|
import msgpack
|
2017-08-09 14:17:58 +02:00
|
|
|
import msgpack.fallback
|
2017-10-03 14:27:29 +02:00
|
|
|
try:
|
|
|
|
from gevent.coros import RLock
|
|
|
|
except:
|
|
|
|
from gevent.lock import RLock
|
2015-07-12 20:36:46 +02:00
|
|
|
|
version 0.2.4, peerPing and peerGetFile commands, old content update bugfix, new network code and protocol, connection share between sites, connection reuse, dont retry bad file more than 3 times in 20 min, multi threaded include file download, shuffle peers before publish, simple internal stats page, dont retry on failed peers, more than 10 peers publish bugfix
2015-02-23 23:33:31 +01:00
|
|
|
from Config import config
|
|
|
|
from Debug import Debug
|
rev134, Removed ZeroMQ dependency and support, GC after every stat page, GC call stat command, Streaming files directly to socket without msgpack overhead, Use listModified to query changed content.json files, Fix urllib memory leak onolder pythons, Fix security tests, Sitemanager testsuite, Announce on site resume, Site publish serves files max 60s
2015-05-03 13:06:43 +02:00
|
|
|
from util import StreamingMsgpack
|
Version 0.3.1, rev238, Connection encryption using TLS, One click site clone feature, Encryption stats, Disable encryption startup parameter, Disable ssl compression startup parameter, Exchange supported encryption methods at handshake, Alternative open port checker, Option to store site privatekey in users.json, Torrent tracker swap, Test for bip32 based site creation, cloning and sslcert creation, Fix for Chrome plugin on OSX, Separate siteSign websocket command, Update pybitcointools to major speedup, Re-add sslwrap for python 0.2.9+, Disable SSL compression to save memory and better performance
2015-06-10 00:29:30 +02:00
|
|
|
from Crypt import CryptConnection
|
2018-01-30 13:59:18 +01:00
|
|
|
from util import helper
|
version 0.2.4, peerPing and peerGetFile commands, old content update bugfix, new network code and protocol, connection share between sites, connection reuse, dont retry bad file more than 3 times in 20 min, multi threaded include file download, shuffle peers before publish, simple internal stats page, dont retry on failed peers, more than 10 peers publish bugfix
2015-02-23 23:33:31 +01:00
|
|
|
|
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
class Connection(object):
|
|
|
|
__slots__ = (
|
2017-04-09 12:02:24 +02:00
|
|
|
"sock", "sock_wrapped", "ip", "port", "cert_pin", "target_onion", "id", "protocol", "type", "server", "unpacker", "req_id",
|
2018-02-08 17:58:44 +01:00
|
|
|
"handshake", "crypt", "connected", "event_connected", "closed", "start_time", "last_recv_time", "is_private_ip",
|
2017-10-03 14:27:29 +02:00
|
|
|
"last_message_time", "last_send_time", "last_sent_time", "incomplete_buff_recv", "bytes_recv", "bytes_sent", "cpu_time", "send_lock",
|
2017-10-13 01:19:34 +02:00
|
|
|
"last_ping_delay", "last_req_time", "last_cmd_sent", "last_cmd_recv", "bad_actions", "sites", "name", "updateName", "waiting_requests", "waiting_streams"
|
2015-07-12 20:36:46 +02:00
|
|
|
)
|
|
|
|
|
2017-04-09 12:02:24 +02:00
|
|
|
def __init__(self, server, ip, port, sock=None, target_onion=None):
|
2015-07-12 20:36:46 +02:00
|
|
|
self.sock = sock
|
|
|
|
self.ip = ip
|
|
|
|
self.port = port
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
self.cert_pin = None
|
|
|
|
if "#" in ip:
|
|
|
|
self.ip, self.cert_pin = ip.split("#")
|
2017-04-09 12:02:24 +02:00
|
|
|
self.target_onion = target_onion # Requested onion adress
|
2015-07-12 20:36:46 +02:00
|
|
|
self.id = server.last_connection_id
|
|
|
|
server.last_connection_id += 1
|
|
|
|
self.protocol = "?"
|
|
|
|
self.type = "?"
|
|
|
|
|
2018-02-08 17:58:44 +01:00
|
|
|
if helper.isPrivateIp(self.ip) and self.ip not in config.ip_local:
|
|
|
|
self.is_private_ip = True
|
|
|
|
else:
|
|
|
|
self.is_private_ip = False
|
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
self.server = server
|
|
|
|
self.unpacker = None # Stream incoming socket messages here
|
|
|
|
self.req_id = 0 # Last request id
|
|
|
|
self.handshake = {} # Handshake info got from peer
|
|
|
|
self.crypt = None # Connection encryption method
|
|
|
|
self.sock_wrapped = False # Socket wrapped to encryption
|
|
|
|
|
|
|
|
self.connected = False
|
|
|
|
self.event_connected = gevent.event.AsyncResult() # Solves on handshake received
|
|
|
|
self.closed = False
|
|
|
|
|
|
|
|
# Stats
|
|
|
|
self.start_time = time.time()
|
|
|
|
self.last_recv_time = 0
|
|
|
|
self.last_message_time = 0
|
|
|
|
self.last_send_time = 0
|
|
|
|
self.last_sent_time = 0
|
|
|
|
self.incomplete_buff_recv = 0
|
|
|
|
self.bytes_recv = 0
|
|
|
|
self.bytes_sent = 0
|
|
|
|
self.last_ping_delay = None
|
|
|
|
self.last_req_time = 0
|
2017-10-13 01:19:34 +02:00
|
|
|
self.last_cmd_sent = None
|
|
|
|
self.last_cmd_recv = None
|
2016-03-12 23:09:26 +01:00
|
|
|
self.bad_actions = 0
|
2016-04-25 02:23:06 +02:00
|
|
|
self.sites = 0
|
2016-11-07 22:52:22 +01:00
|
|
|
self.cpu_time = 0.0
|
2017-10-03 14:27:29 +02:00
|
|
|
self.send_lock = RLock()
|
2015-07-12 20:36:46 +02:00
|
|
|
|
|
|
|
self.name = None
|
|
|
|
self.updateName()
|
|
|
|
|
|
|
|
self.waiting_requests = {} # Waiting sent requests
|
2015-07-25 13:38:58 +02:00
|
|
|
self.waiting_streams = {} # Waiting response file streams
|
2015-07-12 20:36:46 +02:00
|
|
|
|
|
|
|
def updateName(self):
|
|
|
|
self.name = "Conn#%2s %-12s [%s]" % (self.id, self.ip, self.protocol)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return "<%s>" % self.__str__()
|
|
|
|
|
|
|
|
def log(self, text):
|
2018-01-30 18:59:26 +01:00
|
|
|
self.server.log.debug("%s > %s" % (self.name, text.decode("utf8", "ignore")))
|
2015-07-12 20:36:46 +02:00
|
|
|
|
2017-04-09 12:02:24 +02:00
|
|
|
def getValidSites(self):
|
|
|
|
return [key for key, val in self.server.tor_manager.site_onions.items() if val == self.target_onion]
|
|
|
|
|
2016-03-12 23:09:26 +01:00
|
|
|
def badAction(self, weight=1):
|
|
|
|
self.bad_actions += weight
|
2017-01-05 02:25:16 +01:00
|
|
|
if self.bad_actions > 40:
|
2017-02-27 00:02:24 +01:00
|
|
|
self.close("Too many bad actions")
|
2017-01-05 02:25:16 +01:00
|
|
|
elif self.bad_actions > 20:
|
|
|
|
time.sleep(5)
|
|
|
|
|
2016-03-12 23:09:26 +01:00
|
|
|
def goodAction(self):
|
|
|
|
self.bad_actions = 0
|
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
# Open connection to peer and wait for handshake
|
|
|
|
def connect(self):
|
|
|
|
self.log("Connecting...")
|
|
|
|
self.type = "out"
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
if self.ip.endswith(".onion"):
|
|
|
|
if not self.server.tor_manager or not self.server.tor_manager.enabled:
|
|
|
|
raise Exception("Can't connect to onion addresses, no Tor controller present")
|
|
|
|
self.sock = self.server.tor_manager.createSocket(self.ip, self.port)
|
2018-01-30 13:59:18 +01:00
|
|
|
elif config.tor == "always" and helper.isPrivateIp(self.ip) and self.ip not in config.ip_local:
|
|
|
|
raise Exception("Can't connect to local IPs in Tor: always mode")
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
else:
|
2017-10-03 14:30:19 +02:00
|
|
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
2017-10-03 14:31:16 +02:00
|
|
|
|
|
|
|
if "TCP_NODELAY" in dir(socket):
|
|
|
|
self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
|
|
|
|
2017-10-03 14:30:19 +02:00
|
|
|
self.sock.connect((self.ip, int(self.port)))
|
2015-07-12 20:36:46 +02:00
|
|
|
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
# Implicit SSL
|
|
|
|
if self.cert_pin:
|
|
|
|
self.sock = CryptConnection.manager.wrapSocket(self.sock, "tls-rsa", cert_pin=self.cert_pin)
|
|
|
|
self.sock.do_handshake()
|
|
|
|
self.crypt = "tls-rsa"
|
|
|
|
self.sock_wrapped = True
|
2015-07-12 20:36:46 +02:00
|
|
|
|
|
|
|
# Detect protocol
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
self.send({"cmd": "handshake", "req_id": 0, "params": self.getHandshakeInfo()})
|
2015-09-13 12:52:11 +02:00
|
|
|
event_connected = self.event_connected
|
2015-07-12 20:36:46 +02:00
|
|
|
gevent.spawn(self.messageLoop)
|
2015-09-13 12:52:11 +02:00
|
|
|
return event_connected.get() # Wait for handshake
|
2015-07-12 20:36:46 +02:00
|
|
|
|
|
|
|
# Handle incoming connection
|
|
|
|
def handleIncomingConnection(self, sock):
|
|
|
|
self.log("Incoming connection...")
|
2017-10-03 14:31:16 +02:00
|
|
|
|
|
|
|
if "TCP_NODELAY" in dir(socket):
|
|
|
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
self.type = "in"
|
2017-02-16 20:56:07 +01:00
|
|
|
if self.ip not in config.ip_local: # Clearnet: Check implicit SSL
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
try:
|
|
|
|
if sock.recv(1, gevent.socket.MSG_PEEK) == "\x16":
|
|
|
|
self.log("Crypt in connection using implicit SSL")
|
|
|
|
self.sock = CryptConnection.manager.wrapSocket(self.sock, "tls-rsa", True)
|
|
|
|
self.sock_wrapped = True
|
|
|
|
self.crypt = "tls-rsa"
|
|
|
|
except Exception, err:
|
|
|
|
self.log("Socket peek error: %s" % Debug.formatException(err))
|
2015-07-12 20:36:46 +02:00
|
|
|
self.messageLoop()
|
|
|
|
|
|
|
|
# Message loop for connection
|
|
|
|
def messageLoop(self):
|
|
|
|
if not self.sock:
|
|
|
|
self.log("Socket error: No socket found")
|
|
|
|
return False
|
|
|
|
self.protocol = "v2"
|
|
|
|
self.updateName()
|
|
|
|
self.connected = True
|
2016-04-25 02:20:55 +02:00
|
|
|
buff_len = 0
|
2017-10-13 01:21:05 +02:00
|
|
|
req_len = 0
|
2015-07-12 20:36:46 +02:00
|
|
|
|
2017-08-09 14:17:58 +02:00
|
|
|
self.unpacker = msgpack.fallback.Unpacker() # Due memory problems of C version
|
2015-07-12 20:36:46 +02:00
|
|
|
try:
|
2016-09-14 10:54:08 +02:00
|
|
|
while not self.closed:
|
2017-10-03 14:31:39 +02:00
|
|
|
buff = self.sock.recv(64 * 1024)
|
2015-07-12 20:36:46 +02:00
|
|
|
if not buff:
|
|
|
|
break # Connection closed
|
2016-04-25 02:20:55 +02:00
|
|
|
buff_len = len(buff)
|
2015-07-25 13:38:58 +02:00
|
|
|
|
|
|
|
# Statistics
|
2015-07-12 20:36:46 +02:00
|
|
|
self.last_recv_time = time.time()
|
|
|
|
self.incomplete_buff_recv += 1
|
2016-04-25 02:20:55 +02:00
|
|
|
self.bytes_recv += buff_len
|
|
|
|
self.server.bytes_recv += buff_len
|
2017-10-13 01:21:05 +02:00
|
|
|
req_len += buff_len
|
2015-07-25 13:38:58 +02:00
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
if not self.unpacker:
|
2017-08-09 14:17:58 +02:00
|
|
|
self.unpacker = msgpack.fallback.Unpacker()
|
2015-07-12 20:36:46 +02:00
|
|
|
self.unpacker.feed(buff)
|
2015-07-25 13:38:58 +02:00
|
|
|
buff = None
|
2015-07-12 20:36:46 +02:00
|
|
|
for message in self.unpacker:
|
2017-06-19 16:16:13 +02:00
|
|
|
try:
|
2017-10-13 01:21:05 +02:00
|
|
|
# Stats
|
2017-06-19 16:16:13 +02:00
|
|
|
self.incomplete_buff_recv = 0
|
2017-10-13 01:21:05 +02:00
|
|
|
stat_key = message.get("cmd", "unknown")
|
|
|
|
if stat_key == "response" and "to" in message:
|
|
|
|
cmd_sent = self.waiting_requests.get(message["to"], {"cmd": "unknown"})["cmd"]
|
|
|
|
stat_key = "response: %s" % cmd_sent
|
|
|
|
self.server.stat_recv[stat_key]["bytes"] += req_len
|
|
|
|
self.server.stat_recv[stat_key]["num"] += 1
|
|
|
|
if "stream_bytes" in message:
|
|
|
|
self.server.stat_recv[stat_key]["bytes"] += message["stream_bytes"]
|
|
|
|
req_len = 0
|
|
|
|
|
|
|
|
# Handle message
|
2017-06-19 16:16:13 +02:00
|
|
|
if "stream_bytes" in message:
|
|
|
|
self.handleStream(message)
|
|
|
|
else:
|
|
|
|
self.handleMessage(message)
|
|
|
|
except TypeError:
|
|
|
|
raise Exception("Invalid message type: %s" % type(message))
|
2015-07-25 13:38:58 +02:00
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
message = None
|
|
|
|
except Exception, err:
|
|
|
|
if not self.closed:
|
|
|
|
self.log("Socket error: %s" % Debug.formatException(err))
|
2017-02-27 00:02:24 +01:00
|
|
|
self.close("MessageLoop ended") # MessageLoop ended, close connection
|
2015-07-12 20:36:46 +02:00
|
|
|
|
2017-10-03 14:32:02 +02:00
|
|
|
# Stream socket directly to a file
|
|
|
|
def handleStream(self, message):
|
|
|
|
|
|
|
|
read_bytes = message["stream_bytes"] # Bytes left we have to read from socket
|
|
|
|
try:
|
|
|
|
buff = self.unpacker.read_bytes(min(16 * 1024, read_bytes)) # Check if the unpacker has something left in buffer
|
|
|
|
except Exception, err:
|
|
|
|
buff = ""
|
|
|
|
file = self.waiting_streams[message["to"]]
|
|
|
|
if buff:
|
|
|
|
read_bytes -= len(buff)
|
|
|
|
file.write(buff)
|
|
|
|
|
|
|
|
if config.debug_socket:
|
|
|
|
self.log("Starting stream %s: %s bytes (%s from unpacker)" % (message["to"], message["stream_bytes"], len(buff)))
|
|
|
|
|
|
|
|
try:
|
|
|
|
while 1:
|
|
|
|
if read_bytes <= 0:
|
|
|
|
break
|
2017-10-13 01:21:45 +02:00
|
|
|
buff = self.sock.recv(64 * 1024)
|
2017-10-03 14:32:02 +02:00
|
|
|
if not buff:
|
|
|
|
break
|
|
|
|
buff_len = len(buff)
|
|
|
|
read_bytes -= buff_len
|
|
|
|
file.write(buff)
|
|
|
|
|
|
|
|
# Statistics
|
|
|
|
self.last_recv_time = time.time()
|
|
|
|
self.incomplete_buff_recv += 1
|
|
|
|
self.bytes_recv += buff_len
|
|
|
|
self.server.bytes_recv += buff_len
|
|
|
|
except Exception, err:
|
|
|
|
self.log("Stream read error: %s" % Debug.formatException(err))
|
|
|
|
|
|
|
|
if config.debug_socket:
|
|
|
|
self.log("End stream %s" % message["to"])
|
|
|
|
|
|
|
|
self.incomplete_buff_recv = 0
|
2017-10-13 01:21:05 +02:00
|
|
|
self.waiting_requests[message["to"]]["evt"].set(message) # Set the response to event
|
2017-10-03 14:32:02 +02:00
|
|
|
del self.waiting_streams[message["to"]]
|
|
|
|
del self.waiting_requests[message["to"]]
|
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
# My handshake info
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
def getHandshakeInfo(self):
|
|
|
|
# No TLS for onion connections
|
|
|
|
if self.ip.endswith(".onion"):
|
|
|
|
crypt_supported = []
|
|
|
|
else:
|
|
|
|
crypt_supported = CryptConnection.manager.crypt_supported
|
|
|
|
# No peer id for onion connections
|
2017-02-16 20:56:07 +01:00
|
|
|
if self.ip.endswith(".onion") or self.ip in config.ip_local:
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
peer_id = ""
|
|
|
|
else:
|
|
|
|
peer_id = self.server.peer_id
|
|
|
|
# Setup peer lock from requested onion address
|
2017-04-09 12:02:24 +02:00
|
|
|
if self.handshake and self.handshake.get("target_ip", "").endswith(".onion") and self.server.tor_manager.start_onions:
|
|
|
|
self.target_onion = self.handshake.get("target_ip").replace(".onion", "") # My onion address
|
|
|
|
if not self.server.tor_manager.site_onions.values():
|
|
|
|
self.server.log.warning("Unknown target onion address: %s" % self.target_onion)
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
|
|
|
|
handshake = {
|
2015-07-12 20:36:46 +02:00
|
|
|
"version": config.version,
|
|
|
|
"protocol": "v2",
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
"peer_id": peer_id,
|
2015-07-12 20:36:46 +02:00
|
|
|
"fileserver_port": self.server.port,
|
|
|
|
"port_opened": self.server.port_opened,
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
"target_ip": self.ip,
|
2015-07-12 20:36:46 +02:00
|
|
|
"rev": config.rev,
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
"crypt_supported": crypt_supported,
|
2015-07-12 20:36:46 +02:00
|
|
|
"crypt": self.crypt
|
|
|
|
}
|
2017-04-09 12:02:24 +02:00
|
|
|
if self.target_onion:
|
|
|
|
handshake["onion"] = self.target_onion
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
elif self.ip.endswith(".onion"):
|
|
|
|
handshake["onion"] = self.server.tor_manager.getOnion("global")
|
|
|
|
|
|
|
|
return handshake
|
2015-07-12 20:36:46 +02:00
|
|
|
|
|
|
|
def setHandshake(self, handshake):
|
|
|
|
self.handshake = handshake
|
2016-04-25 02:20:55 +02:00
|
|
|
if handshake.get("port_opened", None) is False and "onion" not in handshake: # Not connectable
|
2015-07-12 20:36:46 +02:00
|
|
|
self.port = 0
|
|
|
|
else:
|
|
|
|
self.port = handshake["fileserver_port"] # Set peer fileserver port
|
2015-09-24 22:08:08 +02:00
|
|
|
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
if handshake.get("onion") and not self.ip.endswith(".onion"): # Set incoming connection's onion address
|
|
|
|
self.ip = handshake["onion"] + ".onion"
|
|
|
|
self.updateName()
|
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
# Check if we can encrypt the connection
|
2015-09-02 19:15:55 +02:00
|
|
|
if handshake.get("crypt_supported") and handshake["peer_id"] not in self.server.broken_ssl_peer_ids:
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
if self.ip.endswith(".onion"):
|
|
|
|
crypt = None
|
|
|
|
elif handshake.get("crypt"): # Recommended crypt by server
|
2015-07-12 20:36:46 +02:00
|
|
|
crypt = handshake["crypt"]
|
|
|
|
else: # Select the best supported on both sides
|
|
|
|
crypt = CryptConnection.manager.selectCrypt(handshake["crypt_supported"])
|
|
|
|
|
|
|
|
if crypt:
|
|
|
|
self.crypt = crypt
|
|
|
|
self.event_connected.set(True) # Mark handshake as done
|
2015-09-13 12:52:11 +02:00
|
|
|
self.event_connected = None
|
2015-07-12 20:36:46 +02:00
|
|
|
|
|
|
|
# Handle incoming message
|
|
|
|
def handleMessage(self, message):
|
2017-06-19 16:16:43 +02:00
|
|
|
try:
|
|
|
|
cmd = message["cmd"]
|
|
|
|
except TypeError, AttributeError:
|
|
|
|
cmd = None
|
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
self.last_message_time = time.time()
|
2017-10-13 01:19:34 +02:00
|
|
|
self.last_cmd_recv = cmd
|
2017-06-19 16:16:43 +02:00
|
|
|
if cmd == "response": # New style response
|
2015-07-12 20:36:46 +02:00
|
|
|
if message["to"] in self.waiting_requests:
|
2017-03-02 23:40:30 +01:00
|
|
|
if self.last_send_time and len(self.waiting_requests) == 1:
|
2015-08-16 11:51:00 +02:00
|
|
|
ping = time.time() - self.last_send_time
|
|
|
|
self.last_ping_delay = ping
|
2017-10-13 01:21:05 +02:00
|
|
|
self.waiting_requests[message["to"]]["evt"].set(message) # Set the response to event
|
2015-07-12 20:36:46 +02:00
|
|
|
del self.waiting_requests[message["to"]]
|
|
|
|
elif message["to"] == 0: # Other peers handshake
|
|
|
|
ping = time.time() - self.start_time
|
|
|
|
if config.debug_socket:
|
|
|
|
self.log("Handshake response: %s, ping: %s" % (message, ping))
|
|
|
|
self.last_ping_delay = ping
|
|
|
|
# Server switched to crypt, lets do it also if not crypted already
|
|
|
|
if message.get("crypt") and not self.sock_wrapped:
|
|
|
|
self.crypt = message["crypt"]
|
|
|
|
server = (self.type == "in")
|
2017-03-02 23:40:30 +01:00
|
|
|
self.log("Crypt out connection using: %s (server side: %s, ping: %.3fs)..." % (self.crypt, server, ping))
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
self.sock = CryptConnection.manager.wrapSocket(self.sock, self.crypt, server, cert_pin=self.cert_pin)
|
2015-07-12 20:36:46 +02:00
|
|
|
self.sock.do_handshake()
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
self.sock_wrapped = True
|
|
|
|
|
|
|
|
if not self.sock_wrapped and self.cert_pin:
|
2017-02-27 00:02:24 +01:00
|
|
|
self.close("Crypt connection error: Socket not encrypted, but certificate pin present")
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
return
|
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
self.setHandshake(message)
|
|
|
|
else:
|
|
|
|
self.log("Unknown response: %s" % message)
|
2017-10-13 01:21:05 +02:00
|
|
|
elif cmd:
|
2018-01-19 02:16:33 +01:00
|
|
|
self.server.num_recv += 1
|
2017-06-19 16:16:43 +02:00
|
|
|
if cmd == "handshake":
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
self.handleHandshake(message)
|
2015-07-12 20:36:46 +02:00
|
|
|
else:
|
|
|
|
self.server.handleRequest(self, message)
|
2016-03-21 09:43:53 +01:00
|
|
|
else: # Old style response, no req_id defined
|
2017-06-19 16:16:43 +02:00
|
|
|
self.log("Unknown message, waiting: %s" % self.waiting_requests.keys())
|
Rev903, FeedQuery command only available for ADMIN sites, Show bad files in sidebar, Log unknown messages, Add and check inner_path and site address on sign/verify, Better peer cleanup limit, Log site load times, Testcase for address and inner_path verification, Re-sign testsite with new fields, Fix unnecessary loading screen display when browsing sub-folder with index.html, Fix safari notification width
2016-02-18 11:22:21 +01:00
|
|
|
if self.waiting_requests:
|
|
|
|
last_req_id = min(self.waiting_requests.keys()) # Get the oldest waiting request and set it true
|
2017-10-13 01:21:05 +02:00
|
|
|
self.waiting_requests[last_req_id]["evt"].set(message)
|
Rev903, FeedQuery command only available for ADMIN sites, Show bad files in sidebar, Log unknown messages, Add and check inner_path and site address on sign/verify, Better peer cleanup limit, Log site load times, Testcase for address and inner_path verification, Re-sign testsite with new fields, Fix unnecessary loading screen display when browsing sub-folder with index.html, Fix safari notification width
2016-02-18 11:22:21 +01:00
|
|
|
del self.waiting_requests[last_req_id] # Remove from waiting request
|
2015-07-12 20:36:46 +02:00
|
|
|
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
# Incoming handshake set request
|
|
|
|
def handleHandshake(self, message):
|
|
|
|
if config.debug_socket:
|
|
|
|
self.log("Handshake request: %s" % message)
|
|
|
|
self.setHandshake(message["params"])
|
|
|
|
data = self.getHandshakeInfo()
|
|
|
|
data["cmd"] = "response"
|
|
|
|
data["to"] = message["req_id"]
|
|
|
|
self.send(data) # Send response to handshake
|
|
|
|
# Sent crypt request to client
|
|
|
|
if self.crypt and not self.sock_wrapped:
|
|
|
|
server = (self.type == "in")
|
|
|
|
self.log("Crypt in connection using: %s (server side: %s)..." % (self.crypt, server))
|
|
|
|
try:
|
|
|
|
self.sock = CryptConnection.manager.wrapSocket(self.sock, self.crypt, server, cert_pin=self.cert_pin)
|
|
|
|
self.sock_wrapped = True
|
|
|
|
except Exception, err:
|
|
|
|
self.log("Crypt connection error: %s, adding peerid %s as broken ssl." % (err, message["params"]["peer_id"]))
|
|
|
|
self.server.broken_ssl_peer_ids[message["params"]["peer_id"]] = True
|
2017-02-27 00:02:24 +01:00
|
|
|
self.close("Broken ssl")
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
|
|
|
|
if not self.sock_wrapped and self.cert_pin:
|
2017-02-27 00:02:24 +01:00
|
|
|
self.close("Crypt connection error: Socket not encrypted, but certificate pin present")
|
Version 0.3.5, Rev830, Full Tor mode support with hidden services, Onion stats in Sidebar, GeoDB download fix using Tor, Gray out disabled sites in Stats page, Tor hidden service status in stat page, Benchmark sha256, Skyts tracker out expodie in, 2 new tracker using ZeroNet protocol, Keep SSL cert option between restarts, SSL Certificate pinning support for connections, Site lock support for connections, Certificate pinned connections using implicit SSL, Flood protection whitelist support, Foreign keys support for DB layer, Not support for SQL query helper, 0 length file get bugfix, Pex onion address support, Faster port testing, Faster uPnP port opening, Need connections more often on owned sites, Delay ZeroHello startup message if port check or Tor manager not ready yet, Use lockfiles to avoid double start, Save original socket on proxy monkey patching to get ability to connect localhost directly, Handle atomic write errors, Broken gevent https workaround helper, Rsa crypt functions, Plugin to Bootstrap using ZeroNet protocol
2016-01-05 00:20:52 +01:00
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
# Send data to connection
|
|
|
|
def send(self, message, streaming=False):
|
2017-10-03 14:27:29 +02:00
|
|
|
self.last_send_time = time.time()
|
2015-07-12 20:36:46 +02:00
|
|
|
if config.debug_socket:
|
|
|
|
self.log("Send: %s, to: %s, streaming: %s, site: %s, inner_path: %s, req_id: %s" % (
|
|
|
|
message.get("cmd"), message.get("to"), streaming,
|
|
|
|
message.get("params", {}).get("site"), message.get("params", {}).get("inner_path"),
|
|
|
|
message.get("req_id"))
|
|
|
|
)
|
2017-06-19 16:18:20 +02:00
|
|
|
|
|
|
|
if not self.sock:
|
|
|
|
self.log("Send error: missing socket")
|
|
|
|
return False
|
|
|
|
|
2015-07-25 13:38:58 +02:00
|
|
|
try:
|
2017-10-13 01:21:05 +02:00
|
|
|
stat_key = message.get("cmd", "unknown")
|
|
|
|
if stat_key == "response":
|
|
|
|
stat_key = "response: %s" % self.last_cmd_recv
|
2018-01-19 02:16:33 +01:00
|
|
|
else:
|
|
|
|
self.server.num_sent += 1
|
2017-10-13 01:21:05 +02:00
|
|
|
|
|
|
|
self.server.stat_sent[stat_key]["num"] += 1
|
2015-07-25 13:38:58 +02:00
|
|
|
if streaming:
|
2017-10-03 14:27:29 +02:00
|
|
|
with self.send_lock:
|
|
|
|
bytes_sent = StreamingMsgpack.stream(message, self.sock.sendall)
|
2015-07-25 13:38:58 +02:00
|
|
|
self.bytes_sent += bytes_sent
|
|
|
|
self.server.bytes_sent += bytes_sent
|
2017-10-13 01:21:05 +02:00
|
|
|
self.server.stat_sent[stat_key]["bytes"] += bytes_sent
|
|
|
|
message = None
|
2015-07-25 13:38:58 +02:00
|
|
|
else:
|
|
|
|
data = msgpack.packb(message)
|
|
|
|
self.bytes_sent += len(data)
|
|
|
|
self.server.bytes_sent += len(data)
|
2017-10-13 01:21:05 +02:00
|
|
|
self.server.stat_sent[stat_key]["bytes"] += len(data)
|
|
|
|
message = None
|
2017-10-03 14:27:29 +02:00
|
|
|
with self.send_lock:
|
|
|
|
self.sock.sendall(data)
|
2015-07-25 13:38:58 +02:00
|
|
|
except Exception, err:
|
2017-06-19 16:18:37 +02:00
|
|
|
self.close("Send error: %s" % err)
|
2015-07-25 13:38:58 +02:00
|
|
|
return False
|
2015-07-12 20:36:46 +02:00
|
|
|
self.last_sent_time = time.time()
|
|
|
|
return True
|
|
|
|
|
2017-10-13 01:22:16 +02:00
|
|
|
# Stream file to connection without msgpacking
|
2015-07-25 13:38:58 +02:00
|
|
|
def sendRawfile(self, file, read_bytes):
|
|
|
|
buff = 64 * 1024
|
|
|
|
bytes_left = read_bytes
|
2017-10-13 01:22:16 +02:00
|
|
|
bytes_sent = 0
|
2015-07-25 13:38:58 +02:00
|
|
|
while True:
|
|
|
|
self.last_send_time = time.time()
|
2017-10-13 01:22:16 +02:00
|
|
|
data = file.read(min(bytes_left, buff))
|
|
|
|
bytes_sent += len(data)
|
2017-10-03 14:27:29 +02:00
|
|
|
with self.send_lock:
|
2017-10-13 01:22:16 +02:00
|
|
|
self.sock.sendall(data)
|
2015-07-25 13:38:58 +02:00
|
|
|
bytes_left -= buff
|
|
|
|
if bytes_left <= 0:
|
|
|
|
break
|
2017-10-13 01:22:16 +02:00
|
|
|
self.bytes_sent += bytes_sent
|
|
|
|
self.server.bytes_sent += bytes_sent
|
2017-10-13 01:21:05 +02:00
|
|
|
self.server.stat_sent["raw_file"]["num"] += 1
|
|
|
|
self.server.stat_sent["raw_file"]["bytes"] += bytes_sent
|
2015-07-25 13:38:58 +02:00
|
|
|
return True
|
|
|
|
|
2015-07-12 20:36:46 +02:00
|
|
|
# Create and send a request to peer
|
2015-07-25 13:38:58 +02:00
|
|
|
def request(self, cmd, params={}, stream_to=None):
|
2015-07-12 20:36:46 +02:00
|
|
|
# Last command sent more than 10 sec ago, timeout
|
|
|
|
if self.waiting_requests and self.protocol == "v2" and time.time() - max(self.last_req_time, self.last_recv_time) > 10:
|
2017-10-13 01:21:05 +02:00
|
|
|
self.close("Request %s timeout: %.3fs" % (self.last_cmd_sent, time.time() - self.last_send_time))
|
2015-07-12 20:36:46 +02:00
|
|
|
return False
|
|
|
|
|
|
|
|
self.last_req_time = time.time()
|
2017-10-13 01:19:34 +02:00
|
|
|
self.last_cmd_sent = cmd
|
2015-07-12 20:36:46 +02:00
|
|
|
self.req_id += 1
|
|
|
|
data = {"cmd": cmd, "req_id": self.req_id, "params": params}
|
|
|
|
event = gevent.event.AsyncResult() # Create new event for response
|
2017-10-13 01:21:05 +02:00
|
|
|
self.waiting_requests[self.req_id] = {"evt": event, "cmd": cmd}
|
2015-07-25 13:38:58 +02:00
|
|
|
if stream_to:
|
|
|
|
self.waiting_streams[self.req_id] = stream_to
|
2015-07-12 20:36:46 +02:00
|
|
|
self.send(data) # Send request
|
|
|
|
res = event.get() # Wait until event solves
|
|
|
|
return res
|
|
|
|
|
|
|
|
def ping(self):
|
|
|
|
s = time.time()
|
|
|
|
response = None
|
|
|
|
with gevent.Timeout(10.0, False):
|
|
|
|
try:
|
|
|
|
response = self.request("ping")
|
|
|
|
except Exception, err:
|
|
|
|
self.log("Ping error: %s" % Debug.formatException(err))
|
|
|
|
if response and "body" in response and response["body"] == "Pong!":
|
|
|
|
self.last_ping_delay = time.time() - s
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
|
|
|
# Close connection
|
2017-02-27 00:02:24 +01:00
|
|
|
def close(self, reason="Unknown"):
|
2015-07-12 20:36:46 +02:00
|
|
|
if self.closed:
|
|
|
|
return False # Already closed
|
|
|
|
self.closed = True
|
|
|
|
self.connected = False
|
2015-09-13 12:52:11 +02:00
|
|
|
if self.event_connected:
|
|
|
|
self.event_connected.set(False)
|
2015-07-12 20:36:46 +02:00
|
|
|
|
2017-02-27 00:02:24 +01:00
|
|
|
self.log(
|
|
|
|
"Closing connection: %s, waiting_requests: %s, sites: %s, buff: %s..." %
|
|
|
|
(reason, len(self.waiting_requests), self.sites, self.incomplete_buff_recv)
|
|
|
|
)
|
2015-07-12 20:36:46 +02:00
|
|
|
for request in self.waiting_requests.values(): # Mark pending requests failed
|
2017-10-13 01:21:05 +02:00
|
|
|
request["evt"].set(False)
|
2015-07-12 20:36:46 +02:00
|
|
|
self.waiting_requests = {}
|
2015-07-25 13:38:58 +02:00
|
|
|
self.waiting_streams = {}
|
2016-04-25 02:23:06 +02:00
|
|
|
self.sites = 0
|
2015-07-12 20:36:46 +02:00
|
|
|
self.server.removeConnection(self) # Remove connection from server registry
|
|
|
|
try:
|
|
|
|
if self.sock:
|
|
|
|
self.sock.shutdown(gevent.socket.SHUT_WR)
|
|
|
|
self.sock.close()
|
|
|
|
except Exception, err:
|
|
|
|
if config.debug_socket:
|
|
|
|
self.log("Close error: %s" % err)
|
|
|
|
|
|
|
|
# Little cleanup
|
|
|
|
self.sock = None
|
|
|
|
self.unpacker = None
|
2015-09-13 12:52:11 +02:00
|
|
|
self.event_connected = None
|