protected void receiveQuery(DHTTransportUDPContact originator, Map request, Map response) { trace("received query request"); InetSocketAddress address = originator.getTransportAddress(); response.put("ip", address.getAddress().getHostAddress().getBytes()); response.put("port", new Long(address.getPort())); response.put("ok", new Long(1)); }
protected Map sendConnect( DHTTransportContact target, DHTTransportContact originator, Map originator_client_data) { try { Map request = new HashMap(); request.put("type", new Long(RT_CONNECT_REQUEST)); request.put("origin", encodeContact(originator)); request.put( "port", new Long(((DHTTransportUDPContact) originator).getTransportAddress().getPort())); if (originator_client_data != null) { request.put("client_data", originator_client_data); } Map response = sendRequest(target, request, TRANSFER_TIMEOUT); if (response == null) { return (null); } if (((Long) response.get("type")).intValue() == RT_CONNECT_REPLY) { int result = ((Long) response.get("ok")).intValue(); trace("received connect reply: " + (result == 0 ? "failed" : "ok")); if (result == 1) { Map target_client_data = (Map) response.get("client_data"); if (target_client_data == null) { target_client_data = new HashMap(); } return (target_client_data); } } return (null); } catch (Throwable e) { log(e); return (null); } }
protected int sendBind(DHTTransportContact target) { try { Map request = new HashMap(); request.put("type", new Long(RT_BIND_REQUEST)); Map response = sendRequest(target, request, TRANSFER_TIMEOUT); if (response == null) { return (RESP_FAILED); } if (((Long) response.get("type")).intValue() == RT_BIND_REPLY) { int result = ((Long) response.get("ok")).intValue(); trace("received bind reply: " + (result == 0 ? "failed" : "ok")); if (result == 1) { return (RESP_OK); } } return (RESP_NOT_OK); } catch (Throwable e) { log(e); return (RESP_FAILED); } }
public void setRendezvous(DHTTransportContact target, DHTTransportContact rendezvous) { explicit_rendezvous_map.put(target.getAddress(), rendezvous); if (target.getAddress().equals(dht.getTransport().getLocalContact().getAddress())) { publish(true); } }
protected void receiveBind(DHTTransportUDPContact originator, Map request, Map response) { trace("received bind request"); boolean ok = true; boolean log = true; try { server_mon.enter(); Object[] entry = (Object[]) rendezvous_bindings.get(originator.getAddress().toString()); if (entry == null) { if (rendezvous_bindings.size() == RENDEZVOUS_SERVER_MAX) { ok = false; } } else { // already present, no need to log again log = false; } if (ok) { long now = plugin_interface.getUtilities().getCurrentSystemTime(); rendezvous_bindings.put( originator.getAddress().toString(), new Object[] {originator, new Long(now)}); response.put("port", new Long(originator.getAddress().getPort())); } } finally { server_mon.exit(); } if (log) { log("Rendezvous request from " + originator.getString() + " " + (ok ? "accepted" : "denied")); } response.put("ok", new Long(ok ? 1 : 0)); }
protected void receivePunch(DHTTransportUDPContact originator, Map request, Map response) { trace("received punch request"); boolean ok = false; String target_str = new String((byte[]) request.get("target")); Object[] entry; try { server_mon.enter(); entry = (Object[]) rendezvous_bindings.get(target_str); } finally { server_mon.exit(); } if (entry != null) { DHTTransportUDPContact target = (DHTTransportUDPContact) entry[0]; Map target_client_data = sendConnect(target, originator, (Map) request.get("client_data")); if (target_client_data != null) { response.put("client_data", target_client_data); response.put("port", new Long(target.getTransportAddress().getPort())); ok = true; } } log( "Rendezvous punch request from " + originator.getString() + " to " + target_str + " " + (ok ? "initiated" : "failed")); response.put("ok", new Long(ok ? 1 : 0)); }
protected void rendezvousFailed(DHTTransportContact current_target, boolean tidy) { log("Rendezvous " + (tidy ? "closed" : "failed") + ": " + current_target.getString()); try { pub_mon.enter(); failed_rendezvous.put(current_target.getAddress(), ""); } finally { pub_mon.exit(); } publish(true); }
protected void receiveClose(DHTTransportUDPContact originator, Map request, Map response) { trace("received close request"); final DHTTransportContact current_target = rendezvous_target; if (current_target != null && Arrays.equals(current_target.getID(), originator.getID())) { new AEThread2("DHTNATPuncher:close", true) { public void run() { rendezvousFailed(current_target, true); } }.start(); } response.put("ok", new Long(1)); }
protected boolean sendTunnelOutbound(DHTTransportContact target) { log("Sending tunnel outbound message to " + target.getString()); try { Map message = new HashMap(); message.put("type", new Long(RT_TUNNEL_OUTBOUND)); return (sendTunnelMessage(target, message)); } catch (Throwable e) { log(e); return (false); } }
protected Map receiveRequest(DHTTransportUDPContact originator, Map data) { int type = ((Long) data.get("type")).intValue(); Map response = new HashMap(); switch (type) { case RT_BIND_REQUEST: { response.put("type", new Long(RT_BIND_REPLY)); receiveBind(originator, data, response); break; } case RT_CLOSE_REQUEST: { response.put("type", new Long(RT_CLOSE_REPLY)); receiveClose(originator, data, response); break; } case RT_QUERY_REQUEST: { response.put("type", new Long(RT_QUERY_REPLY)); receiveQuery(originator, data, response); break; } case RT_PUNCH_REQUEST: { response.put("type", new Long(RT_PUNCH_REPLY)); receivePunch(originator, data, response); break; } case RT_CONNECT_REQUEST: { response.put("type", new Long(RT_CONNECT_REPLY)); receiveConnect(originator, data, response); break; } case RT_TUNNEL_INBOUND: { receiveTunnelInbound(originator, data); response = null; break; } case RT_TUNNEL_OUTBOUND: { receiveTunnelOutbound(originator, data); response = null; break; } default: { response = null; break; } } return (response); }
protected void receiveConnect(DHTTransportContact rendezvous, Map request, Map response) { trace("received connect request"); boolean ok = false; // ensure that we've received this from our current rendezvous node DHTTransportContact rt = rendezvous_target; if (rt != null && rt.getAddress().equals(rendezvous.getAddress())) { final DHTTransportUDPContact target = decodeContact((byte[]) request.get("origin")); if (target != null) { int transport_port = 0; Long indirect_port = (Long) request.get("port"); if (indirect_port != null) { transport_port = indirect_port.intValue(); } if (transport_port != 0) { InetSocketAddress existing_address = target.getTransportAddress(); if (transport_port != existing_address.getPort()) { target.setTransportAddress( new InetSocketAddress(existing_address.getAddress(), transport_port)); } } Map originator_client_data = (Map) request.get("client_data"); boolean no_tunnel = false; if (originator_client_data == null) { originator_client_data = new HashMap(); } else { no_tunnel = originator_client_data.get("_notunnel") != null; } if (no_tunnel) { log("Received message from " + target.getString()); } else { log("Received connect request from " + target.getString()); // ping the origin a few times to try and establish a tunnel UTTimerEvent event = timer.addPeriodicEvent( 3000, new UTTimerEventPerformer() { private int pings = 1; public void perform(UTTimerEvent ev) { if (pings > 3) { ev.cancel(); return; } pings++; if (sendTunnelInbound(target)) { ev.cancel(); } } }); if (sendTunnelInbound(target)) { event.cancel(); } } Map client_data = adapter.getClientData(target.getTransportAddress(), originator_client_data); if (client_data == null) { client_data = new HashMap(); } response.put("client_data", client_data); ok = true; } else { log("Connect request: failed to decode target"); } } else { log("Connect request from invalid rendezvous: " + rendezvous.getString()); } response.put("ok", new Long(ok ? 1 : 0)); }
protected Map sendPunch( DHTTransportContact rendezvous, final DHTTransportUDPContact target, Map originator_client_data, boolean no_tunnel) { AESemaphore wait_sem = new AESemaphore("DHTNatPuncher::sendPunch"); Object[] wait_data = new Object[] {target, wait_sem, new Integer(0)}; try { try { punch_mon.enter(); oustanding_punches.add(wait_data); } finally { punch_mon.exit(); } Map request = new HashMap(); request.put("type", new Long(RT_PUNCH_REQUEST)); request.put("target", target.getAddress().toString().getBytes()); if (originator_client_data != null) { if (no_tunnel) { originator_client_data.put("_notunnel", new Long(1)); } request.put("client_data", originator_client_data); } // for a message payload (i.e. no_tunnel) we double the initiator timeout to give // more chance for reasonable size messages to get through as they have to go through // 2 xfer processes Map response = sendRequest(rendezvous, request, no_tunnel ? TRANSFER_TIMEOUT * 2 : TRANSFER_TIMEOUT); if (response == null) { return (null); } if (((Long) response.get("type")).intValue() == RT_PUNCH_REPLY) { int result = ((Long) response.get("ok")).intValue(); trace( "received " + (no_tunnel ? "message" : "punch") + " reply: " + (result == 0 ? "failed" : "ok")); if (result == 1) { // pick up port changes from the rendezvous Long indirect_port = (Long) response.get("port"); if (indirect_port != null) { int transport_port = indirect_port.intValue(); if (transport_port != 0) { InetSocketAddress existing_address = target.getTransportAddress(); if (transport_port != existing_address.getPort()) { target.setTransportAddress( new InetSocketAddress(existing_address.getAddress(), transport_port)); } } } if (!no_tunnel) { // ping the target a few times to try and establish a tunnel UTTimerEvent event = timer.addPeriodicEvent( 3000, new UTTimerEventPerformer() { private int pings = 1; public void perform(UTTimerEvent event) { if (pings > 3) { event.cancel(); return; } pings++; if (sendTunnelOutbound(target)) { event.cancel(); } } }); if (sendTunnelOutbound(target)) { event.cancel(); } // give the other end a few seconds to kick off some tunnel events to us if (wait_sem.reserve(10000)) { event.cancel(); } } // routers often fiddle with the port when not mapped so we need to grab the right one to // use // for direct communication // first priority goes to direct tunnel messages received int transport_port = 0; try { punch_mon.enter(); transport_port = ((Integer) wait_data[2]).intValue(); } finally { punch_mon.exit(); } if (transport_port != 0) { InetSocketAddress existing_address = target.getTransportAddress(); if (transport_port != existing_address.getPort()) { target.setTransportAddress( new InetSocketAddress(existing_address.getAddress(), transport_port)); } } Map target_client_data = (Map) response.get("client_data"); if (target_client_data == null) { target_client_data = new HashMap(); } return (target_client_data); } } return (null); } catch (Throwable e) { log(e); return (null); } finally { try { punch_mon.enter(); oustanding_punches.remove(wait_data); } finally { punch_mon.exit(); } } }