def tunnel(self, conn, env): logging.debug('TUNNEL') if 'HTTP_X_MIFCHO_TUNNEL_ID' in env: # We requested the tunnel logging.debug('We requested the tunnel...') tunnel = self.cm.tunnels[env['HTTP_X_MIFCHO_TUNNEL_ID']] tunnel.peer_connection = conn messages.send_response(conn, code = 101, message = 'Switching Protocols', headers = [ ('X-Mifcho-Id', env['mifcho.id']) ] ) tunnel.event.set() else: # We did not request the tunnel so this is an indirect tunnel carrier. logging.debug('We did not request it...') ep_address = ( env['HTTP_X_MIFCHO_TUNNEL_ENDPOINTHOST'], int(headers['X_MIFCHO_TUNNEL_ENDPOINTPORT']) ) ep_conn = self.cm.connect(ep_address) if conn and ep_conn: logging.debug('Successfully contacted endpoint...') tunnel = Tunnel.fromconnections(conn, ep_conn) tunnel.id = str(uuid.uuid4()) self.cm.add_tunnel(tunnel) messages.send_response(conn, code = 101, message = 'Switching Protocols', headers = [ ('X-Mifcho-Id', self.cm.identifier) ] ) pipe = Piper(self.cm, conn, ep_conn, 4096, sink_recovery=(ep_address, None)) pipe.start() self.cm.pipes.append(pipe) else: logging.error('Failed connecting to endpoint [%s].' % repr(address)) self.cm.teardown(conn)
def connect(self, address, peer_id=None, use_tls=False): """Create a connection to address. Possible via another mifcho instance.""" logging.debug( "Connecting to: %s %s %s." % (pprint.pformat(address), pprint.pformat(peer_id), pprint.pformat(use_tls)) ) conn = None peer = self.get_peer(peer_id) if not peer and not peer_id: # Connect "directly" to address try: conn = Connection.fromaddress(address, use_tls) if conn: # Add to opened connections self.opened.append(conn) except socket.error: logging.error("%s when connecting to %s." % (sys.exc_info()[1], address)) except: logging.error("Unexpected error", exc_info=3) elif peer and peer.interface: # Connect via peer interface # Extract address and parameters of peer interface. peer_address = (peer.interface[0], peer.interface[1]) try: peer_conn = self.connect(peer_address) # Socket Connect messages.send_request( # Send TunnelReq peer_conn, type="POST", url="/mifcho/tunnel", headers=[ ("X-Mifcho-Id", self.identifier), ("X-Mifcho-Tunnel-EndpointHost", address[0]), ("X-Mifcho-Tunnel-EndpointPort", address[1]), ], ) resp = (version, status, reason, headers) = messages.get_response(peer_conn) # Wait for response except: logging.error("Failed connecting to socket!") logging.debug("Failed receiving response!", exc_info=3) peer_conn = None resp = (version, status, reason, headers) = ("", 404, "Not Found", []) conn = peer_conn elif peer and not peer.interface: # Connect via peer control-line # and "callback". peer.lock.acquire() # CRITICAL ZONE START... tunnel = Tunnel.fromconnections(None, None) self.add_tunnel(tunnel) try: # Send request for tunnel messages.send_request( peer.connection, type="POST", url="/mifcho/tunnel_request", headers=[ ("X-Mifcho-Id", self.identifier), ("X-Mifcho-Tunnel-Id", tunnel.id), ("X-Mifcho-Tunnel-EndpointHost", address[0]), ("X-Mifcho-Tunnel-EndpointPort", address[1]), ], ) except: logging.error("Error sending request to peer!", exc_info=3) try: # Wait for response resp = (version, status, reason, headers) = messages.get_response(peer.connection) except: logging.error("Failed receiving response!") logging.debug("Failed receiving response!", exc_info=3) resp = (version, status, reason, headers) = ("", 404, "Not Found", []) peer.lock.release() # CRITICAL ZONE END.... if int(status) == 200: # All is good # Wait for PeerHandler to set tunnel-event wait_for_tunnel = True while status == 200 and self.running and wait_for_tunnel: tunnel.event.wait(1) wait_for_tunnel = not tunnel.event.is_set() conn = tunnel.peer_connection else: conn = None elif peer_id and not peer: logging.error("Could not find peer %s." % repr(peer_id)) logging.debug("Peers=[%s]" % repr(self.peers)) else: logging.error("Invalid params.") return conn