def run(self): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(self.client_addr) s.connect(self.server_addr) self.conn = Connection(s, self.server_addr) receiver = threading.Thread(target=self.receive, daemon=True) receiver.start() udp_receiver = threading.Thread(target=self.receive_udp, daemon=True) udp_receiver.start() try: while True: msg = input() if msg == 'U' or msg == 'M': with open('ascii.txt', 'r', encoding='ascii') as ascii_art: content = ascii_art.read() if msg == 'U': addr = self.server_addr else: addr = MULTICAST_ADDR send_udp(content, addr, self.client_addr) else: self.conn.send_msg(msg) except KeyboardInterrupt: print('Received Ctrl+C.') except ConnectionError: print('Connection to server closed.')
def connect(redis_conn, key): """ Establishes connection with a node to: 1) Send version message 2) Receive version and verack message 3) Send getaddr message 4) Receive addr message containing list of peering nodes Stores state and height for node in Redis. """ handshake_msgs = [] addr_msgs = [] redis_conn.hset(key, 'state', "") # Set Redis hash for a new node (address, port, services) = key[5:].split("-", 2) services = int(services) height = redis_conn.get('height') if height: height = int(height) proxy = None if address.endswith(".onion"): proxy = SETTINGS['tor_proxy'] conn = Connection((address, int(port)), (SETTINGS['source_address'], 0), socket_timeout=SETTINGS['socket_timeout'], proxy=proxy, protocol_version=SETTINGS['protocol_version'], to_services=services, from_services=SETTINGS['services'], user_agent=SETTINGS['user_agent'], height=height, relay=SETTINGS['relay']) try: logging.debug("Connecting to %s", conn.to_addr) conn.open() handshake_msgs = conn.handshake() addr_msgs = conn.getaddr() except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("%s: %s", conn.to_addr, err) finally: conn.close() gevent.sleep(0.3) redis_pipe = redis_conn.pipeline() if len(handshake_msgs) > 0: version_msg = handshake_msgs[0] from_services = version_msg.get('services', 0) if from_services != services: logging.debug("%s Expected %d, got %d for services", conn.to_addr, services, from_services) key = "node:{}-{}-{}".format(address, port, from_services) height_key = "height:{}-{}-{}".format(address, port, from_services) redis_pipe.setex(height_key, SETTINGS['max_age'], version_msg.get('height', 0)) now = int(time.time()) peers = enumerate_node(redis_pipe, addr_msgs, now) logging.debug("%s Peers: %d", conn.to_addr, peers) redis_pipe.hset(key, 'state', "up") redis_pipe.execute()
def task(): """ Assigned to a worker to retrieve (pop) a node from the reachable set and attempt to establish and maintain connection with the node. """ node = REDIS_CONN.spop('reachable') if node is None: return (address, port, height) = eval(node) handshake_msgs = [] connection = Connection((address, port), socket_timeout=SETTINGS['socket_timeout'], user_agent=SETTINGS['user_agent'], height=height) try: connection.open() handshake_msgs = connection.handshake() except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("Closing {} ({})".format(connection.to_addr, err)) connection.close() if len(handshake_msgs) == 0: return keepalive(connection, handshake_msgs[0])
def execute(self, code, callback = None): s = attempt_new_socket(self.port) try: connection = Connection(s) connection.write_message( 1, str(code)) (msgtype, payload) = connection.read_message() success = msgtype == 2 print "[%s] [%s]" % (msgtype, payload) if callback is not None: callback(success, payload) return success finally: s.close()
def _getaddr(self, node, port): """ Establishes connection with a node to: 1) Send version message 2) Receive version and verack message 3) Send getaddr message 4) Receive addr message containing list of adjacent nodes """ to_addr = (node, port) conn = Connection(to_addr, socket_timeout=SETTINGS['socket_timeout'], user_agent=SETTINGS['user_agent'], start_height=SETTINGS['start_height']) error = "" handshake_msgs = [] addr_msg = {} try: conn.open() handshake_msgs = conn.handshake() addr_msg = conn.getaddr() except (ProtocolError, socket.error) as err: error = str(err) logging.debug("{}: {} dropped".format(err, to_addr)) finally: conn.close() nodes = None degree = 0 # Record version information for the remote node if len(handshake_msgs) > 0: if not self.database.has_node(node, table="nodes_version"): self.database.add_node_version(node, handshake_msgs[0]) nodes = [] if 'addr_list' in addr_msg: nodes = self.get_nodes_from_addr_list(addr_msg['addr_list']) degree = len(nodes) # Cache the result in database for reuse in subsequent getaddr() # calls for the same node. self.database.add_node_getaddr(node, nodes, error, degree) return nodes
def connect(redis_conn, key): """ Establishes connection with a node to: 1) Send version message 2) Receive version and verack message 3) Send getaddr message 4) Receive addr message containing list of peering nodes Stores state and height for node in Redis. """ handshake_msgs = [] addr_msgs = [] redis_conn.hset(key, 'state', "") # Set Redis hash for a new node (address, port, services) = key[5:].split("-", 2) height = redis_conn.get('height') if height: height = int(height) conn = Connection((address, int(port)), (SETTINGS['source_address'], 0), socket_timeout=SETTINGS['socket_timeout'], proxy=SETTINGS['proxy'], protocol_version=SETTINGS['protocol_version'], to_services=int(services), from_services=SETTINGS['services'], user_agent=SETTINGS['user_agent'], height=height, relay=SETTINGS['relay']) try: logging.debug("Connecting to %s", conn.to_addr) conn.open() handshake_msgs = conn.handshake() addr_msgs = conn.getaddr() except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("%s: %s", conn.to_addr, err) finally: conn.close() gevent.sleep(0.3) redis_pipe = redis_conn.pipeline() if len(handshake_msgs) > 0: height_key = "height:{}-{}-{}".format(address, port, services) redis_pipe.setex(height_key, SETTINGS['max_age'], handshake_msgs[0].get('height', 0)) now = int(time.time()) peers = enumerate_node(redis_pipe, addr_msgs, now) logging.debug("%s Peers: %d", conn.to_addr, peers) redis_pipe.hset(key, 'state', "up") redis_pipe.execute()
def connect(redis_conn, key): """ Establishes connection with a node to: 1) Send version message 2) Receive version and verack message 3) Send getaddr message 4) Receive addr message containing list of peering nodes Stores state and height for node in Redis. """ handshake_msgs = [] addr_msgs = [] redis_conn.hset(key, 'state', "") # Set Redis hash for a new node (address, port) = key[5:].split("-", 1) height = redis_conn.get('height') if height is None: height = 0 else: height = int(height) connection = Connection((address, int(port)), socket_timeout=SETTINGS['socket_timeout'], user_agent=SETTINGS['user_agent'], height=height) try: logging.debug("Connecting to {}".format(connection.to_addr)) connection.open() handshake_msgs = connection.handshake() addr_msgs = connection.getaddr() except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("{}: {}".format(connection.to_addr, err)) finally: connection.close() gevent.sleep(0.3) redis_pipe = redis_conn.pipeline() if len(handshake_msgs) > 0: height_key = "height:{}-{}".format(address, port) redis_pipe.setex(height_key, SETTINGS['max_age'], handshake_msgs[0].get('height', 0)) now = int(time.time()) peers = enumerate_node(redis_pipe, addr_msgs, now) logging.debug("{} Peers: {}".format(connection.to_addr, peers)) redis_pipe.hset(key, 'state', "up") redis_pipe.execute()
def task(): """ Assigned to a worker to retrieve (pop) a node from the reachable set and attempt to establish and maintain connection with the node. """ node = REDIS_CONN.spop('reachable') if node is None: return (address, port, services, height) = eval(node) node = (address, port) if REDIS_CONN.sadd('open', node) == 0: logging.debug("Connection exists: %s", node) return handshake_msgs = [] conn = Connection(node, (SETTINGS['source_address'], 0), socket_timeout=SETTINGS['socket_timeout'], protocol_version=SETTINGS['protocol_version'], to_services=services, from_services=SETTINGS['services'], user_agent=SETTINGS['user_agent'], height=height, relay=SETTINGS['relay']) try: conn.open() handshake_msgs = conn.handshake() except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("Closing %s (%s)", node, err) conn.close() if len(handshake_msgs) == 0: REDIS_CONN.srem('open', node) return Keepalive(conn=conn, version_msg=handshake_msgs[0]).keepalive() conn.close() REDIS_CONN.srem('open', node)
def connect(redis_conn, key): """ Establishes connection with a node to: 1) Send version message 2) Receive version and verack message 3) Send getaddr message 4) Receive addr message containing list of peering nodes Stores node in Redis. """ handshake_msgs = [] addr_msg = {} redis_conn.hset(key, TAG_FIELD, "") # Set Redis hash for a new node (address, port) = key[5:].split("-", 1) start_height = int(redis_conn.get('start_height')) connection = Connection((address, int(port)), socket_timeout=SETTINGS['socket_timeout'], user_agent=SETTINGS['user_agent'], start_height=start_height) try: connection.open() handshake_msgs = connection.handshake() addr_msg = connection.getaddr() except ProtocolError as err: logging.debug("{}".format(err)) except socket.error as err: logging.debug("{}".format(err)) finally: connection.close() redis_pipe = redis_conn.pipeline() if len(handshake_msgs) > 0: addNode(handshake_msgs[0]) enumerate_node(redis_pipe, key, handshake_msgs[0], addr_msg) redis_pipe.hset(key, TAG_FIELD, GREEN) redis_pipe.execute()
def task(): """ Assigned to a worker to retrieve (pop) a node from the reachable set and attempt to establish and maintain connection with the node. """ node = REDIS_CONN.spop('reachable') (address, port, start_height) = eval(node) handshake_msgs = [] connection = Connection((address, port), socket_timeout=SETTINGS['socket_timeout'], user_agent=SETTINGS['user_agent'], start_height=start_height) try: connection.open() handshake_msgs = connection.handshake() except ProtocolError as err: connection.close() except socket.error as err: connection.close() if len(handshake_msgs) > 0: keepalive(connection, handshake_msgs[0])
def handle(self): global last_request connection = Connection(self.request, verbose = verbose) try: while 1: (msgtype, msg) = connection.read_message() last_request = datetime.now() logging.debug( "[%i] [%s]" % (msgtype, msg)) if msgtype == 1: # execute code km = initialize_km() out, error = execute(km, msg) logging.debug( "[complete] [%s] [%s]" % (out, error)) if error is None: connection.write_message( 2, out ) else: connection.write_message( 3, error['error'] ) else: raise RuntimeError("unknown msgtype : %s" % str(msgtype)) except SocketDisconnected: logging.info("Client disconnected")
def task(): """ Assigned to a worker to retrieve (pop) a node from the reachable set and attempt to establish and maintain connection with the node. """ node = REDIS_CONN.spop('reachable') if node is None: return (address, port, services, height) = eval(node) node = (address, port) # Check if prefix has hit its limit cidr_key = None if ":" in address and SETTINGS['ipv6_prefix'] < 128: cidr = ip_to_network(address, SETTINGS['ipv6_prefix']) cidr_key = 'ping:cidr:{}'.format(cidr) nodes = REDIS_CONN.incr(cidr_key) logging.info("+CIDR %s: %d", cidr, nodes) if nodes > SETTINGS['nodes_per_ipv6_prefix']: logging.info("CIDR limit reached: %s", cidr) nodes = REDIS_CONN.decr(cidr_key) logging.info("-CIDR %s: %d", cidr, nodes) return if REDIS_CONN.sadd('open', node) == 0: logging.info("Connection exists: %s", node) if cidr_key: nodes = REDIS_CONN.decr(cidr_key) logging.info("-CIDR %s: %d", cidr, nodes) return proxy = None if address.endswith(".onion"): proxy = SETTINGS['tor_proxy'] handshake_msgs = [] conn = Connection(node, (SETTINGS['source_address'], 0), socket_timeout=SETTINGS['socket_timeout'], proxy=proxy, protocol_version=SETTINGS['protocol_version'], to_services=services, from_services=SETTINGS['services'], user_agent=SETTINGS['user_agent'], height=height, relay=SETTINGS['relay']) try: logging.debug("Connecting to %s", conn.to_addr) conn.open() handshake_msgs = conn.handshake() except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("Closing %s (%s)", node, err) conn.close() if len(handshake_msgs) == 0: if cidr_key: nodes = REDIS_CONN.decr(cidr_key) logging.info("-CIDR %s: %d", cidr, nodes) REDIS_CONN.srem('open', node) return if address.endswith(".onion"): # Map local port to .onion node local_port = conn.socket.getsockname()[1] logging.info("%s: 127.0.0.1:%d", conn.to_addr, local_port) REDIS_CONN.set('onion:{}'.format(local_port), conn.to_addr) Keepalive(conn=conn, version_msg=handshake_msgs[0]).keepalive() conn.close() if cidr_key: nodes = REDIS_CONN.decr(cidr_key) logging.info("-CIDR %s: %d", cidr, nodes) REDIS_CONN.srem('open', node)
def connect(redis_conn, key): """ Establishes connection with a node to: 1) Send version message 2) Receive version and verack message 3) Send getaddr message 4) Receive addr message containing list of peering nodes Stores state and height for node in Redis. """ handshake_msgs = [] addr_msgs = [] redis_conn.set(key, "") # Set Redis key for a new node (address, port, services) = key[5:].split("-", 2) services = int(services) height = redis_conn.get('height') if height: height = int(height) proxy = None if address.endswith(".onion"): proxy = CONF['tor_proxy'] conn = Connection((address, int(port)), (CONF['source_address'], 0), magic_number=CONF['magic_number'], socket_timeout=CONF['socket_timeout'], proxy=proxy, protocol_version=CONF['protocol_version'], to_services=services, from_services=CONF['services'], user_agent=CONF['user_agent'], height=height, relay=CONF['relay']) print(address) print(int(port)) print(CONF['magic_number']) print(CONF['socket_timeout']) print(proxy) print(CONF['protocol_version']) print(CONF['services']) print(CONF['user_agent']) print(height) print(CONF['relay']) try: logging.debug("Connecting to %s", conn.to_addr) conn.open() handshake_msgs = conn.handshake() print("OK") except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("%s: %s", conn.to_addr, err) print("just die") redis_pipe = redis_conn.pipeline() if len(handshake_msgs) > 0: try: conn.getaddr(block=False) except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("%s: %s", conn.to_addr, err) else: addr_wait = 0 while addr_wait < CONF['socket_timeout']: addr_wait += 1 gevent.sleep(0.3) try: msgs = conn.get_messages(commands=['addr']) except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("%s: %s", conn.to_addr, err) break if msgs and any([msg['count'] > 1 for msg in msgs]): addr_msgs = msgs break version_msg = handshake_msgs[0] from_services = version_msg.get('services', 0) if from_services != services: logging.debug("%s Expected %d, got %d for services", conn.to_addr, services, from_services) key = "node:{}-{}-{}".format(address, port, from_services) height_key = "height:{}-{}-{}".format(address, port, from_services) redis_pipe.setex(height_key, CONF['max_age'], version_msg.get('height', 0)) now = int(time.time()) (peers, excluded) = enumerate_node(redis_pipe, addr_msgs, now) logging.debug("%s Peers: %d (Excluded: %d)", conn.to_addr, peers, excluded) redis_pipe.set(key, "") redis_pipe.sadd('up', key) conn.close() redis_pipe.execute()
def connect(network, address, port, to_services, network_data, user_agent=None, explicit_p2p=False, p2p_nodes=True, from_services=None, keepalive=False, attempt=1): now = datetime.datetime.utcnow() results = {'network': network, 'address': address, 'port': port, 'timestamp': now, 'seen': 0, 'attempt': attempt} try: handshake_msgs = [] new_addrs = [] proxy = None if address.endswith(".onion"): proxy = CONF['tor_proxy'] conn = Connection((address, port), (CONF['source_address'], 0), magic_number=network_data['magic_number'], socket_timeout=CONF['socket_timeout'], proxy=proxy, protocol_version=int(network_data['protocol_version']), min_protocol_version=network_data['min_protocol_version'], to_services=int(to_services), from_services=int(from_services or network_data['services']), user_agent=user_agent or CONF['user_agent'], height=int(network_data['height']), relay=CONF['relay']) try: conn.open() except (ProtocolError, ConnectionError, socket.error) as err: results['error'] = str(err) logging.debug("connection failed %s %s", type(err), err) else: try: handshake_msgs = conn.handshake() assert handshake_msgs results['seen'] = 1 results['height'] = int(handshake_msgs[0]['height']) results['version'] = int(handshake_msgs[0]['version']) results['user_agent'] = handshake_msgs[0]['user_agent'].decode() results['services'] = int(handshake_msgs[0]['services']) except (ProtocolError, ConnectionError, socket.error, AssertionError) as err: results['error'] = str(err) logging.debug("handshake failed %s", err) msgs = [] if len(handshake_msgs) > 0 and (p2p_nodes or explicit_p2p): getaddr = True chance = CONF['getaddr_prop'] if chance < 1.0 and p2p_nodes and not explicit_p2p and not "--seed" in sys.argv: if np.random.rand() > chance: getaddr = False if getaddr: try: conn.getaddr(block=False) msgs = msgs + conn.get_messages(commands=[b"addr"]) time.sleep(5) msgs = msgs + conn.get_messages(commands=[b"addr"]) except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("getaddr failed %s", err) if keepalive: Keepalive(conn, 10).keepalive(addr=True if p2p_nodes else False) for msg in msgs: if msg['count'] > 1: ts = now.timestamp() for addr in msg['addr_list']: if ts - addr['timestamp'] < 12 * 60 * 60: # within 6 hours new_addrs.append(addr) conn.close() return results, new_addrs except Exception as err: logging.warning("unspecified connection error: %s", err) return {}, []
def handler(client, address, config, connection_id): connection_id = hex(connection_id)[2:] connection_id = "0"*(10-len(connection_id)) + connection_id try: print(f"[{connection_id}][info]: new connection from {address[0]}:{address[1]}") conn = TCPSocketConnection(client) result = conn.read_buffer() if result.read_varint() != 0: # if it isn't minecraft protocol print(f"[{connection_id}][warning]: this connection does not use the miencraft protocol !") client.close() return proto_version = result.read_varint() host = result.read_utf() print(f"[{connection_id}][info]: protocol version :{proto_version}") print(f"[{connection_id}][info]: host :{host}") print(f"[{connection_id}][info]: port :{result.read_ushort()}") connection_type = result.read_varint() if connection_type == 2: # login buf = conn.read_buffer() buf.read_varint() print(f"[{connection_id}][info]: login tried with {buf.read_utf()}'s account") data = Connection() data.write_varint(0) with open("kick_payload.json") as fp: data.write_utf(json.dumps(json.loads(fp.read()))) conn.write_buffer(data) client.close() return elif connection_type != 1: # if unkown connection type print(f"[{connection_id}][waring]: this client requested an unknown connection type !") client.close() return # status query while True: result = conn.read_buffer() action = result.read_varint() if action == 0: print(f"[{connection_id}][info]: status requested") data = Connection() data.write_varint(0) with open("status_payload.json") as fp: status = json.load(fp) status["version"]["protocol"] = proto_version status["players"]["online"] = get_player_amount(config["rush_hour"], config["min_player"], config["random"]) status["players"]["max"] = config["player_slot"] if os.path.isfile("favicon.png"): with open("favicon.png", "rb") as fp: status["favicon"] = "data:image/png;base64,"+base64.b64encode(fp.read()).decode() data.write_utf(json.dumps(status)) conn.write_buffer(data) elif action == 1: data = Connection() data.write_varint(1) data.write_long(result.read_long()) conn.write_buffer(data) print(f"[{connection_id}][info]: pong !") else: print(f"[{connection_id}][warning]: not implemented requests ! {action}") break client.close() except OSError as e: # connection closed client.close() except Exception as e: print(f"[{connection_id}][error]: {e}") client.close()
def task(): """ Assigned to a worker to retrieve (pop) a node from the reachable set and attempt to establish and maintain connection with the node. """ node = REDIS_CONN.spop('reachable') if node is None: return (address, port, services, height) = eval(node) node = (address, port) # Check if prefix has hit its limit cidr_key = None if ":" in address and CONF['ipv6_prefix'] < 128: cidr = ip_to_network(address, CONF['ipv6_prefix']) cidr_key = 'ping:cidr:{}'.format(cidr) nodes = REDIS_CONN.incr(cidr_key) logging.info("+CIDR %s: %d", cidr, nodes) if nodes > CONF['nodes_per_ipv6_prefix']: logging.info("CIDR limit reached: %s", cidr) nodes = REDIS_CONN.decr(cidr_key) logging.info("-CIDR %s: %d", cidr, nodes) return if REDIS_CONN.sadd('open', node) == 0: logging.info("Connection exists: %s", node) if cidr_key: nodes = REDIS_CONN.decr(cidr_key) logging.info("-CIDR %s: %d", cidr, nodes) return proxy = None if address.endswith(".onion"): proxy = random.choice(CONF['tor_proxies']) handshake_msgs = [] conn = Connection(node, (CONF['source_address'], 0), magic_number=CONF['magic_number'], socket_timeout=CONF['socket_timeout'], proxy=proxy, protocol_version=CONF['protocol_version'], to_services=services, from_services=CONF['services'], user_agent=CONF['user_agent'], height=height, relay=CONF['relay']) try: logging.debug("Connecting to %s", conn.to_addr) conn.open() handshake_msgs = conn.handshake() except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("Closing %s (%s)", node, err) conn.close() if len(handshake_msgs) == 0: if cidr_key: nodes = REDIS_CONN.decr(cidr_key) logging.info("-CIDR %s: %d", cidr, nodes) REDIS_CONN.srem('open', node) return if address.endswith(".onion"): # Map local port to .onion node local_port = conn.socket.getsockname()[1] logging.info("Local port %s: %d", conn.to_addr, local_port) REDIS_CONN.set('onion:{}'.format(local_port), conn.to_addr) Keepalive(conn=conn, version_msg=handshake_msgs[0]).keepalive() conn.close() if cidr_key: nodes = REDIS_CONN.decr(cidr_key) logging.info("-CIDR %s: %d", cidr, nodes) REDIS_CONN.srem('open', node)
class Client: def __init__(self, server_host='127.0.0.1', server_port=8000, client_host='127.0.0.1', client_port=8001): self.server_addr = (server_host, server_port) self.client_addr = (client_host, client_port) self.conn = None def run(self): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(self.client_addr) s.connect(self.server_addr) self.conn = Connection(s, self.server_addr) receiver = threading.Thread(target=self.receive, daemon=True) receiver.start() udp_receiver = threading.Thread(target=self.receive_udp, daemon=True) udp_receiver.start() try: while True: msg = input() if msg == 'U' or msg == 'M': with open('ascii.txt', 'r', encoding='ascii') as ascii_art: content = ascii_art.read() if msg == 'U': addr = self.server_addr else: addr = MULTICAST_ADDR send_udp(content, addr, self.client_addr) else: self.conn.send_msg(msg) except KeyboardInterrupt: print('Received Ctrl+C.') except ConnectionError: print('Connection to server closed.') def receive(self): try: while True: msg = self.conn.recv_msg() print('>>> {}'.format(msg)) except ConnectionError: self.conn.close() def receive_udp(self): with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as u_sock: with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as m_sock: u_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) u_sock.bind(self.client_addr) host = socket.gethostbyname(socket.gethostname()) m_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) m_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(MULTICAST_ADDR[0]) + socket.inet_aton(host)) m_sock.bind(MULTICAST_ADDR) ev_loop = select.epoll() u_fd, m_fd = u_sock.fileno(), m_sock.fileno() ev_loop.register(u_fd, select.EPOLLIN) ev_loop.register(m_fd, select.EPOLLIN) try: while True: events = ev_loop.poll() for file_no, event in events: if event | select.EPOLLIN: if file_no == u_fd: msg = u_sock.recv(MAX_UDP_SIZE) else: msg, addr = m_sock.recvfrom(MAX_UDP_SIZE) if addr == self.client_addr: continue print(msg.decode()) except ConnectionError: self.conn.close()
def connect(redis_conn, key): """ Establishes connection with a node to: 1) Send version message 2) Receive version and verack message 3) Send getaddr message 4) Receive addr message containing list of peering nodes Stores state and height for node in Redis. """ handshake_msgs = [] addr_msgs = [] redis_conn.set(key, "") # Set Redis key for a new node (address, port, services) = key[5:].split("-", 2) services = int(services) height = redis_conn.get('height') if height: height = int(height) proxy = None if address.endswith(".onion"): proxy = CONF['tor_proxy'] conn = Connection((address, int(port)), (CONF['source_address'], 0), magic_number=CONF['magic_number'], socket_timeout=CONF['socket_timeout'], proxy=proxy, protocol_version=CONF['protocol_version'], to_services=services, from_services=CONF['services'], user_agent=CONF['user_agent'], height=height, relay=CONF['relay']) try: logging.debug("Connecting to %s", conn.to_addr) conn.open() handshake_msgs = conn.handshake() except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("%s: %s", conn.to_addr, err) redis_pipe = redis_conn.pipeline() if len(handshake_msgs) > 0: try: conn.getaddr(block=False) except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("%s: %s", conn.to_addr, err) else: addr_wait = 0 while addr_wait < CONF['socket_timeout']: addr_wait += 1 gevent.sleep(0.3) try: msgs = conn.get_messages(commands=['addr']) except (ProtocolError, ConnectionError, socket.error) as err: logging.debug("%s: %s", conn.to_addr, err) break if msgs and any([msg['count'] > 1 for msg in msgs]): addr_msgs = msgs break version_msg = handshake_msgs[0] from_services = version_msg.get('services', 0) if from_services != services: logging.debug("%s Expected %d, got %d for services", conn.to_addr, services, from_services) key = "node:{}-{}-{}".format(address, port, from_services) height_key = "height:{}-{}-{}".format(address, port, from_services) redis_pipe.setex(height_key, CONF['max_age'], version_msg.get('height', 0)) now = int(time.time()) (peers, excluded) = enumerate_node(redis_pipe, addr_msgs, now) logging.debug("%s Peers: %d (Excluded: %d)", conn.to_addr, peers, excluded) redis_pipe.set(key, "") redis_pipe.sadd('up', key) conn.close() redis_pipe.execute()
class ClientHandler: LOGIN_MSG = 'Choose a nickname.' HELLO_MSG = 'You are in, {}!' NICK_TAKEN_MSG = 'Nickname {} is taken, choose another one.' SHUTDOWN_MSG = 'Server shut down and you were disconnected.' def __init__(self, sock, addr, server): self.server = server self.conn = Connection(sock, addr) self.inbox = Queue(maxsize=MAX_CLIENT_QUEUE) self.nickname = None self.channel = None @property def addr(self): return self.conn.addr def init(self): try: self.conn.send_msg(self.LOGIN_MSG) while True: try: nickname = self.conn.recv_msg() self.server.register_client(nickname, self) self.server.addr_client[self.addr] = self self.nickname = nickname self.conn.send_msg(self.HELLO_MSG.format(nickname)) break except NickTakenError: self.conn.send_msg(self.NICK_TAKEN_MSG.format(nickname)) except OSError: self.shutdown() # Connection fully established. self.server.subscribe(self.nickname, 'default') self.channel = self.server.channels['default'] self.in_channel() def shutdown(self): try: self.conn.send_msg(self.SHUTDOWN_MSG) self.conn.close() except OSError: pass # yeah, really self.channel.unsub(self.nickname) self.server.remove_client(self.nickname) def in_channel(self): receiver = threading.Thread(target=self.process_inbox, daemon=True) receiver.start() try: while True: msg = self.conn.recv_msg() msg = '{}: {}'.format(self.nickname, msg) self.channel.publish(('tcp', msg), self.nickname) except ConnectionError: self.shutdown() def process_inbox(self): try: while True: kin, msg = self.inbox.get() if kin == 'udp': send_udp(msg, self.addr) else: self.conn.send_msg(msg) except ConnectionError: self.shutdown() def push(self, msg): self.inbox.put(msg) def handle_udp(self, msg): self.channel.publish(('udp', msg), self.nickname)
def __init__(self, sock, addr, server): self.server = server self.conn = Connection(sock, addr) self.inbox = Queue(maxsize=MAX_CLIENT_QUEUE) self.nickname = None self.channel = None