Search in sources :

Example 6 with DHTTransportContact

use of com.biglybt.core.dht.transport.DHTTransportContact in project BiglyBT by BiglySoftware.

the class PairingManagerTunnelHandler method updateRegistrationData.

protected void updateRegistrationData(Map<String, Object> payload) {
    int puncher_num = 0;
    int num_registered = 0;
    for (DHTNATPuncher nat_ipv4 : nat_punchers_ipv4) {
        DHTTransportContact rend = nat_ipv4.getRendezvous();
        DHTTransportContact lc = nat_ipv4.getLocalContact();
        if (rend != null && lc != null) {
            puncher_num++;
            InetSocketAddress rend_address = rend.getTransportAddress();
            num_registered++;
            payload.put("rc_v4-" + puncher_num, rend_address.getAddress().getHostAddress() + ":" + rend_address.getPort());
            if (puncher_num == 1) {
                payload.put("rl_v4", lc.getExternalAddress().getAddress().getHostAddress() + ":" + lc.getAddress().getPort());
            }
        }
    }
    puncher_num = 0;
    for (DHTNATPuncher nat_ipv6 : nat_punchers_ipv6) {
        DHTTransportContact rend = nat_ipv6.getRendezvous();
        DHTTransportContact lc = nat_ipv6.getLocalContact();
        if (rend != null && lc != null) {
            puncher_num++;
            InetSocketAddress rend_address = rend.getTransportAddress();
            num_registered++;
            payload.put("rc_v6-" + puncher_num, rend_address.getAddress().getHostAddress() + ":" + rend_address.getPort());
            if (puncher_num == 1) {
                payload.put("rl_v6", lc.getExternalAddress().getAddress().getHostAddress() + ":" + lc.getAddress().getPort());
            }
        }
    }
    if (num_registered != last_punchers_registered) {
        last_punchers_registered = num_registered;
        manager.updateSRPState();
    }
}
Also used : DHTNATPuncher(com.biglybt.core.dht.nat.DHTNATPuncher) DHTTransportContact(com.biglybt.core.dht.transport.DHTTransportContact) InetSocketAddress(java.net.InetSocketAddress)

Example 7 with DHTTransportContact

use of com.biglybt.core.dht.transport.DHTTransportContact in project BiglyBT by BiglySoftware.

the class PairingManagerTunnelHandler method start.

private void start() {
    synchronized (this) {
        if (started) {
            return;
        }
        started = true;
    }
    N_3072 = fromHex("FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 29024E08" + "8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD EF9519B3 CD3A431B" + "302B0A6D F25F1437 4FE1356D 6D51C245 E485B576 625E7EC6 F44C42E9" + "A637ED6B 0BFF5CB6 F406B7ED EE386BFB 5A899FA5 AE9F2411 7C4B1FE6" + "49286651 ECE45B3D C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8" + "FD24CF5F 83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B E39E772C" + "180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9 DE2BCBF6 95581718" + "3995497C EA956AE5 15D22618 98FA0510 15728E5A 8AAAC42D AD33170D" + "04507A33 A85521AB DF1CBA64 ECFB8504 58DBEF0A 8AEA7157 5D060C7D" + "B3970F85 A6E1E4C7 ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226" + "1AD2EE6B F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31 43DB5BFC" + "E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF");
    G_3072 = BigInteger.valueOf(5);
    try {
        PluginInterface dht_pi = core.getPluginManager().getPluginInterfaceByClass(DHTPlugin.class);
        if (dht_pi == null) {
            throw (new Exception("DHT Plugin not found"));
        }
        DHTPlugin dht_plugin = (DHTPlugin) dht_pi.getPlugin();
        if (!dht_plugin.isEnabled()) {
            throw (new Exception("DHT Plugin is disabled"));
        }
        DHT[] dhts = dht_plugin.getDHTs();
        List<DHTNATPuncher> punchers = new ArrayList<>();
        for (DHT dht : dhts) {
            int net = dht.getTransport().getNetwork();
            if (net == DHT.NW_AZ_MAIN) {
                DHTNATPuncher primary_puncher = dht.getNATPuncher();
                if (primary_puncher != null) {
                    punchers.add(primary_puncher);
                    nat_punchers_ipv4.add(primary_puncher);
                    for (int i = 1; i <= 2; i++) {
                        DHTNATPuncher puncher = primary_puncher.getSecondaryPuncher();
                        punchers.add(puncher);
                        nat_punchers_ipv4.add(puncher);
                    }
                }
            } else if (net == DHT.NW_AZ_MAIN_V6) {
            /*
					 * no point in this atm as we don't support v6 tunnels

					DHTNATPuncher puncher = dht.getNATPuncher();

					if ( puncher != null ){

						punchers.add( puncher );

						nat_punchers_ipv6.add( puncher );

						puncher = puncher.getSecondaryPuncher();

						punchers.add( puncher );

						nat_punchers_ipv6.add( puncher );
					}
					*/
            }
        }
        if (punchers.size() == 0) {
            throw (new Exception("No suitable DHT instances available"));
        }
        for (DHTNATPuncher p : punchers) {
            p.forceActive(true);
            p.addListener(new DHTNATPuncherListener() {

                @Override
                public void rendezvousChanged(DHTTransportContact rendezvous) {
                    System.out.println("active: " + rendezvous.getString());
                    synchronized (PairingManagerTunnelHandler.this) {
                        if (update_event == null) {
                            update_event = SimpleTimer.addEvent("PMT:defer", SystemTime.getOffsetTime(15 * 1000), new TimerEventPerformer() {

                                @Override
                                public void perform(TimerEvent event) {
                                    synchronized (PairingManagerTunnelHandler.this) {
                                        update_event = null;
                                    }
                                    System.out.println("    updating");
                                    manager.updateNeeded();
                                }
                            });
                        }
                    }
                }
            });
        }
        core.getNATTraverser().registerHandler(new NATTraversalHandler() {

            private final Map<Long, Object[]> server_map = new LinkedHashMap<Long, Object[]>(10, 0.75f, true) {

                @Override
                protected boolean removeEldestEntry(Map.Entry<Long, Object[]> eldest) {
                    return size() > 10;
                }
            };

            @Override
            public int getType() {
                return (NATTraverser.TRAVERSE_REASON_PAIR_TUNNEL);
            }

            @Override
            public String getName() {
                return ("Pairing Tunnel");
            }

            @Override
            public Map process(InetSocketAddress originator, Map data) {
                if (SRP_VERIFIER == null || !active) {
                    return (null);
                }
                boolean good_request = false;
                try {
                    Map result = new HashMap();
                    Long session = (Long) data.get("sid");
                    if (session == null) {
                        return (null);
                    }
                    InetAddress tunnel_originator;
                    try {
                        tunnel_originator = InetAddress.getByAddress((byte[]) data.get("origin"));
                    } catch (Throwable e) {
                        Debug.out("originator decode failed: " + data);
                        return (null);
                    }
                    System.out.println("PairManagerTunnelHander: incoming message - session=" + session + ", payload=" + data + " from " + tunnel_originator + " via " + originator);
                    SRP6Server server;
                    BigInteger B;
                    synchronized (server_map) {
                        Object[] entry = server_map.get(session);
                        if (entry == null) {
                            long diff = SystemTime.getMonotonousTime() - last_server_create_time;
                            if (diff < 5000) {
                                try {
                                    long sleep = 5000 - diff;
                                    System.out.println("Sleeping for " + sleep + " before starting srp");
                                    Thread.sleep(sleep);
                                } catch (Throwable e) {
                                }
                            }
                            server = new SRP6Server();
                            server.init(N_3072, G_3072, SRP_VERIFIER, new SHA256Digest(), RandomUtils.SECURE_RANDOM);
                            B = server.generateServerCredentials();
                            server_map.put(session, new Object[] { server, B });
                            last_server_create_time = SystemTime.getMonotonousTime();
                            total_servers++;
                        } else {
                            server = (SRP6Server) entry[0];
                            B = (BigInteger) entry[1];
                        }
                    }
                    Long op = (Long) data.get("op");
                    if (op == 1) {
                        result.put("op", 2);
                        result.put("s", SRP_SALT);
                        result.put("b", B.toByteArray());
                        good_request = true;
                        if (data.containsKey("test")) {
                            manager.recordRequest("SRP Test", originator.getAddress().getHostAddress(), true);
                        }
                    } else if (op == 3) {
                        boolean log_error = true;
                        try {
                            long diff = SystemTime.getMonotonousTime() - last_server_agree_time;
                            if (diff < 5000) {
                                try {
                                    long sleep = 5000 - diff;
                                    System.out.println("Sleeping for " + sleep + " before completing srp");
                                    Thread.sleep(sleep);
                                } catch (Throwable e) {
                                }
                            }
                            BigInteger A = new BigInteger((byte[]) data.get("a"));
                            BigInteger serverS = server.calculateSecret(A);
                            byte[] shared_secret = serverS.toByteArray();
                            Cipher decipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                            byte[] key = new byte[16];
                            System.arraycopy(shared_secret, 0, key, 0, 16);
                            SecretKeySpec secret = new SecretKeySpec(key, "AES");
                            decipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec((byte[]) data.get("enc_iv")));
                            byte[] dec = decipher.doFinal((byte[]) data.get("enc_data"));
                            String json_str = new String(dec, "UTF-8");
                            if (!json_str.startsWith("{")) {
                                log_error = false;
                                throw (new Exception("decode failed"));
                            }
                            JSONObject dec_json = (JSONObject) JSONUtils.decodeJSON(json_str);
                            String tunnel_url = (String) dec_json.get("url");
                            String service_id = new String((byte[]) data.get("service"), "UTF-8");
                            String endpoint_url = (String) dec_json.get("endpoint");
                            boolean ok = createTunnel(tunnel_originator, session, service_id, secret, tunnel_url, endpoint_url);
                            result.put("op", 4);
                            result.put("status", ok ? "ok" : "failed");
                            good_request = true;
                        } catch (Throwable e) {
                            result.put("op", 4);
                            result.put("status", "failed");
                            if (e instanceof BadPaddingException || e instanceof IllegalBlockSizeException) {
                                log_error = false;
                            }
                            if (log_error) {
                                e.printStackTrace();
                            }
                        } finally {
                            last_server_agree_time = SystemTime.getMonotonousTime();
                        }
                    }
                    return (result);
                } finally {
                    if (!good_request) {
                        manager.recordRequest("SRP", originator.getAddress().getHostAddress(), false);
                    }
                }
            }
        });
        SimpleTimer.addPeriodicEvent("pm:tunnel:stats", 30 * 1000, new TimerEventPerformer() {

            @Override
            public void perform(TimerEvent event) {
                synchronized (tunnels) {
                    if (tunnels.size() > 0) {
                        System.out.println("PairTunnels: " + tunnels.size());
                        for (PairManagerTunnel t : tunnels.values()) {
                            System.out.println("\t" + t.getString());
                        }
                    }
                }
            }
        });
    } catch (Throwable e) {
        Debug.out(e);
        init_fail = Debug.getNestedExceptionMessage(e);
        manager.updateSRPState();
    }
}
Also used : NATTraversalHandler(com.biglybt.core.nat.NATTraversalHandler) InetSocketAddress(java.net.InetSocketAddress) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) BadPaddingException(javax.crypto.BadPaddingException) DHT(com.biglybt.core.dht.DHT) SecretKeySpec(javax.crypto.spec.SecretKeySpec) DHTPlugin(com.biglybt.plugin.dht.DHTPlugin) DHTNATPuncherListener(com.biglybt.core.dht.nat.DHTNATPuncherListener) DHTNATPuncher(com.biglybt.core.dht.nat.DHTNATPuncher) PluginInterface(com.biglybt.pif.PluginInterface) IllegalBlockSizeException(javax.crypto.IllegalBlockSizeException) IOException(java.io.IOException) BadPaddingException(javax.crypto.BadPaddingException) DHTTransportContact(com.biglybt.core.dht.transport.DHTTransportContact) JSONObject(org.json.simple.JSONObject) SHA256Digest(org.gudy.bouncycastle.crypto.digests.SHA256Digest) SRP6Server(org.gudy.bouncycastle.crypto.agreement.srp.SRP6Server) BigInteger(java.math.BigInteger) JSONObject(org.json.simple.JSONObject) IvParameterSpec(javax.crypto.spec.IvParameterSpec) Cipher(javax.crypto.Cipher) InetAddress(java.net.InetAddress)

Example 8 with DHTTransportContact

use of com.biglybt.core.dht.transport.DHTTransportContact in project BiglyBT by BiglySoftware.

the class DHTDBImpl method queriesComplete.

protected void queriesComplete(byte[] survey_my_id, Map<DHTDBMapping, List<DHTTransportContact>> mapping_to_node_map, Map<DHTTransportContact, Object[]> replies) {
    Map<SurveyContactState, List<DHTDBMapping>> store_ops = new HashMap<>();
    try {
        this_mon.enter();
        if (!Arrays.equals(survey_my_id, router.getID())) {
            logger.log("Survey abandoned - router changed");
            return;
        }
        if (DEBUG_SURVEY) {
            System.out.println("Queries complete (replies=" + replies.size() + ")");
        }
        Map<DHTDBMapping, int[]> totals = new HashMap<>();
        for (Map.Entry<DHTTransportContact, Object[]> entry : replies.entrySet()) {
            DHTTransportContact contact = entry.getKey();
            HashWrapper hw = new HashWrapper(contact.getID());
            SurveyContactState contact_state = survey_state.get(hw);
            if (contact_state != null) {
                contact_state.updateContactDetails(contact);
            } else {
                contact_state = new SurveyContactState(contact);
                survey_state.put(hw, contact_state);
            }
            contact_state.updateUseTime();
            Object[] temp = entry.getValue();
            List<DHTDBMapping> mappings = (List<DHTDBMapping>) temp[0];
            List<byte[]> reply = (List<byte[]>) temp[1];
            if (reply == null) {
                contact_state.contactFailed();
            } else {
                contact_state.contactOK();
                if (mappings.size() != reply.size()) {
                    Debug.out("Inconsistent: mappings=" + mappings.size() + ", reply=" + reply.size());
                    continue;
                }
                Iterator<DHTDBMapping> it1 = mappings.iterator();
                Iterator<byte[]> it2 = reply.iterator();
                while (it1.hasNext()) {
                    DHTDBMapping mapping = it1.next();
                    byte[] rep = it2.next();
                    if (rep == null) {
                        contact_state.removeMapping(mapping);
                    } else {
                        // must match against our short-key mapping for consistency
                        DHTDBMapping mapping_to_check = stored_values_prefix_map.get(mapping.getShortKey());
                        if (mapping_to_check == null) {
                        // deleted
                        } else {
                            byte[] k = mapping_to_check.getKey().getBytes();
                            int rep_len = rep.length;
                            if (rep_len < 2 || rep_len >= k.length) {
                                Debug.out("Invalid rep_len: " + rep_len);
                                continue;
                            }
                            boolean match = true;
                            int offset = k.length - rep_len;
                            for (int i = 0; i < rep_len; i++) {
                                if (rep[i] != k[i + offset]) {
                                    match = false;
                                    break;
                                }
                            }
                            if (match) {
                                contact_state.addMapping(mapping);
                            } else {
                                contact_state.removeMapping(mapping);
                            }
                        }
                    }
                }
                Set<DHTDBMapping> contact_mappings = contact_state.getMappings();
                for (DHTDBMapping m : contact_mappings) {
                    int[] t = totals.get(m);
                    if (t == null) {
                        // one for local node + 1 for them
                        t = new int[] { 2 };
                        totals.put(m, t);
                    } else {
                        t[0]++;
                    }
                }
            }
        }
        for (Map.Entry<DHTDBMapping, List<DHTTransportContact>> entry : mapping_to_node_map.entrySet()) {
            DHTDBMapping mapping = entry.getKey();
            List<DHTTransportContact> contacts = entry.getValue();
            int[] t = totals.get(mapping);
            int copies;
            if (t == null) {
                // us!
                copies = 1;
            } else {
                copies = t[0];
            }
            Iterator<DHTDBValueImpl> values = mapping.getValues();
            if (values.hasNext()) {
                int max_replication_factor = -1;
                while (values.hasNext()) {
                    DHTDBValueImpl value = values.next();
                    int rf = value.getReplicationFactor();
                    if (rf > max_replication_factor) {
                        max_replication_factor = rf;
                    }
                }
                if (max_replication_factor == 0) {
                    continue;
                }
                if (max_replication_factor > router.getK()) {
                    max_replication_factor = router.getK();
                }
                if (copies < max_replication_factor) {
                    int required = max_replication_factor - copies;
                    List<SurveyContactState> potential_targets = new ArrayList<>();
                    List<byte[]> addresses = new ArrayList<>(contacts.size());
                    for (DHTTransportContact c : contacts) {
                        if (c.getProtocolVersion() < DHTTransportUDP.PROTOCOL_VERSION_REPLICATION_CONTROL3) {
                            continue;
                        }
                        addresses.add(AddressUtils.getAddressBytes(c.getAddress()));
                        SurveyContactState contact_state = survey_state.get(new HashWrapper(c.getID()));
                        if (contact_state != null && !contact_state.testMapping(mapping)) {
                            potential_targets.add(contact_state);
                        }
                    }
                    Set<HashWrapper> bad_addresses = new HashSet<>();
                    for (byte[] a1 : addresses) {
                        for (byte[] a2 : addresses) {
                            if (a1 == a2 || a1.length != a2.length || a1.length != 4) {
                                continue;
                            }
                            if (a1[0] == a2[0] && a1[1] == a2[1]) {
                                log("/16 match on " + ByteFormatter.encodeString(a1) + "/" + ByteFormatter.encodeString(a2));
                                bad_addresses.add(new HashWrapper(a1));
                                bad_addresses.add(new HashWrapper(a2));
                            }
                        }
                    }
                    final byte[] key = mapping.getKey().getBytes();
                    Collections.sort(potential_targets, new Comparator<SurveyContactState>() {

                        @Override
                        public int compare(SurveyContactState o1, SurveyContactState o2) {
                            boolean o1_bad = o1.getConsecFails() >= 2;
                            boolean o2_bad = o2.getConsecFails() >= 2;
                            if (o1_bad == o2_bad) {
                                if (false) {
                                    long res = o2.getCreationTime() - o1.getCreationTime();
                                    if (res < 0) {
                                        return (-1);
                                    } else if (res > 0) {
                                        return (1);
                                    } else {
                                        return (0);
                                    }
                                } else {
                                    return (control.computeAndCompareDistances(o1.getContact().getID(), o2.getContact().getID(), key));
                                }
                            } else {
                                if (o1_bad) {
                                    return (1);
                                } else {
                                    return (-1);
                                }
                            }
                        }
                    });
                    int avail = Math.min(required, potential_targets.size());
                    for (int i = 0; i < avail; i++) {
                        SurveyContactState target = potential_targets.get(i);
                        if (bad_addresses.size() > 0 && bad_addresses.contains(new HashWrapper(AddressUtils.getAddressBytes(target.getContact().getAddress())))) {
                            // make it look like this target has the mapping as we don't want to store it there but we want to treat it as
                            // if it has it, effectively reducing availability but not skewing storage in favour of potentially malicious nodes
                            target.addMapping(mapping);
                        } else {
                            List<DHTDBMapping> m = store_ops.get(target);
                            if (m == null) {
                                m = new ArrayList<>();
                                store_ops.put(target, m);
                            }
                            m.add(mapping);
                        }
                    }
                }
            }
        }
    } finally {
        this_mon.exit();
        survey_in_progress = false;
    }
    logger.log("Survey complete - " + store_ops.size() + " store ops");
    if (DEBUG_SURVEY) {
        System.out.println("Store ops: " + store_ops.size());
    }
    for (Map.Entry<SurveyContactState, List<DHTDBMapping>> store_op : store_ops.entrySet()) {
        final SurveyContactState contact = store_op.getKey();
        final List<DHTDBMapping> keys = store_op.getValue();
        final byte[][] store_keys = new byte[keys.size()][];
        final DHTTransportValue[][] store_values = new DHTTransportValue[store_keys.length][];
        for (int i = 0; i < store_keys.length; i++) {
            DHTDBMapping mapping = keys.get(i);
            store_keys[i] = mapping.getKey().getBytes();
            List<DHTTransportValue> v = new ArrayList<>();
            Iterator<DHTDBValueImpl> it = mapping.getValues();
            while (it.hasNext()) {
                DHTDBValueImpl value = it.next();
                if (!value.isLocal()) {
                    v.add(value.getValueForRelay(local_contact));
                }
            }
            store_values[i] = v.toArray(new DHTTransportValue[v.size()]);
        }
        final DHTTransportContact d_contact = contact.getContact();
        final Runnable store_exec = new Runnable() {

            @Override
            public void run() {
                if (DEBUG_SURVEY) {
                    System.out.println("Storing " + keys.size() + " on " + d_contact.getString() + " - rand=" + d_contact.getRandomID());
                }
                control.putDirectEncodedKeys(store_keys, "Replication forward", store_values, d_contact, new DHTOperationAdapter() {

                    @Override
                    public void complete(boolean timeout) {
                        try {
                            this_mon.enter();
                            if (timeout) {
                                contact.contactFailed();
                            } else {
                                contact.contactOK();
                                for (DHTDBMapping m : keys) {
                                    contact.addMapping(m);
                                }
                            }
                        } finally {
                            this_mon.exit();
                        }
                    }
                });
            }
        };
        if (d_contact.getRandomIDType() != DHTTransportContact.RANDOM_ID_TYPE1) {
            Debug.out("derp");
        }
        if (d_contact.getRandomID() == 0) {
            d_contact.sendFindNode(new DHTTransportReplyHandlerAdapter() {

                @Override
                public void findNodeReply(DHTTransportContact _contact, DHTTransportContact[] _contacts) {
                    store_exec.run();
                }

                @Override
                public void failed(DHTTransportContact _contact, Throwable _error) {
                    try {
                        this_mon.enter();
                        contact.contactFailed();
                    } finally {
                        this_mon.exit();
                    }
                }
            }, d_contact.getProtocolVersion() >= DHTTransportUDP.PROTOCOL_VERSION_ANTI_SPOOF2 ? new byte[0] : new byte[20], DHT.FLAG_LOOKUP_FOR_STORE);
        } else {
            store_exec.run();
        }
    }
}
Also used : DHTTransportValue(com.biglybt.core.dht.transport.DHTTransportValue) DHTTransportContact(com.biglybt.core.dht.transport.DHTTransportContact) DHTTransportReplyHandlerAdapter(com.biglybt.core.dht.transport.DHTTransportReplyHandlerAdapter)

Example 9 with DHTTransportContact

use of com.biglybt.core.dht.transport.DHTTransportContact in project BiglyBT by BiglySoftware.

the class DHTDBImpl method survey.

protected void survey() {
    if (survey_in_progress) {
        return;
    }
    if (DEBUG_SURVEY) {
        System.out.println("surveying");
    }
    checkCacheExpiration(false);
    final byte[] my_id = router.getID();
    if (DEBUG_SURVEY) {
        System.out.println("    my_id=" + ByteFormatter.encodeString(my_id));
    }
    final ByteArrayHashMap<DHTTransportContact> id_map = new ByteArrayHashMap<>();
    List<DHTTransportContact> all_contacts = control.getClosestContactsList(my_id, router.getK() * 3, true);
    for (DHTTransportContact contact : all_contacts) {
        id_map.put(contact.getID(), contact);
    }
    byte[] max_key = my_id;
    byte[] max_dist = null;
    final List<HashWrapper> applicable_keys = new ArrayList<>();
    try {
        this_mon.enter();
        long now = SystemTime.getMonotonousTime();
        Iterator<SurveyContactState> s_it = survey_state.values().iterator();
        while (s_it.hasNext()) {
            if (s_it.next().timeout(now)) {
                s_it.remove();
            }
        }
        Iterator<DHTDBMapping> it = stored_values.values().iterator();
        Set<HashWrapper> existing_times = new HashSet<>(survey_mapping_times.keySet());
        while (it.hasNext()) {
            DHTDBMapping mapping = it.next();
            HashWrapper hw = mapping.getKey();
            if (existing_times.size() > 0) {
                existing_times.remove(hw);
            }
            if (!applyRF(mapping)) {
                continue;
            }
            applicable_keys.add(hw);
            byte[] key = hw.getBytes();
            /*
				List<DHTTransportContact>	contacts = control.getClosestKContactsList( key, true );

				for ( DHTTransportContact c: contacts ){

					id_map.put( c.getID(), c );
				}
				*/
            byte[] distance = control.computeDistance(my_id, key);
            if (max_dist == null || control.compareDistances(distance, max_dist) > 0) {
                max_dist = distance;
                max_key = key;
            }
        }
        for (HashWrapper hw : existing_times) {
            survey_mapping_times.remove(hw);
        }
        logger.log("Survey starts: state size=" + survey_state.size() + ", all keys=" + stored_values.size() + ", applicable keys=" + applicable_keys.size());
    } finally {
        this_mon.exit();
    }
    if (DEBUG_SURVEY) {
        System.out.println("    max_key=" + ByteFormatter.encodeString(max_key) + ", dist=" + ByteFormatter.encodeString(max_dist) + ", initial_contacts=" + id_map.size());
    }
    if (max_key == my_id) {
        logger.log("Survey complete - no applicable values");
        return;
    }
    // obscure key so we don't leak any keys
    byte[] obscured_key = control.getObfuscatedKey(max_key);
    final int[] requery_count = { 0 };
    final boolean[] processing = { false };
    try {
        survey_in_progress = true;
        control.lookupEncoded(obscured_key, "Neighbourhood survey: basic", 0, true, new DHTOperationAdapter() {

            private final List<DHTTransportContact> contacts = new ArrayList<>();

            private boolean survey_complete;

            @Override
            public void found(DHTTransportContact contact, boolean is_closest) {
                if (is_closest) {
                    synchronized (contacts) {
                        if (!survey_complete) {
                            contacts.add(contact);
                        }
                    }
                }
            }

            @Override
            public void complete(boolean timeout) {
                boolean requeried = false;
                try {
                    int hits = 0;
                    int misses = 0;
                    // find the closest miss to us and recursively search
                    byte[] min_dist = null;
                    byte[] min_id = null;
                    synchronized (contacts) {
                        for (DHTTransportContact c : contacts) {
                            byte[] id = c.getID();
                            if (id_map.containsKey(id)) {
                                hits++;
                            } else {
                                misses++;
                                if (id_map.size() >= MAX_SURVEY_SIZE) {
                                    log("Max survery size exceeded");
                                    break;
                                }
                                id_map.put(id, c);
                                byte[] distance = control.computeDistance(my_id, id);
                                if (min_dist == null || control.compareDistances(distance, min_dist) < 0) {
                                    min_dist = distance;
                                    min_id = id;
                                }
                            }
                        }
                        contacts.clear();
                    }
                    if (misses > 0 && misses * 100 / (hits + misses) >= 25 && id_map.size() < MAX_SURVEY_SIZE) {
                        if (requery_count[0]++ < 5) {
                            if (DEBUG_SURVEY) {
                                System.out.println("requery at " + ByteFormatter.encodeString(min_id));
                            }
                            // don't need to obscure here as its a node-id
                            control.lookupEncoded(min_id, "Neighbourhood survey: level=" + requery_count[0], 0, true, this);
                            requeried = true;
                        } else {
                            if (DEBUG_SURVEY) {
                                System.out.println("requery limit exceeded");
                            }
                        }
                    } else {
                        if (DEBUG_SURVEY) {
                            System.out.println("super-neighbourhood=" + id_map.size() + " (hits=" + hits + ", misses=" + misses + ", level=" + requery_count[0] + ")");
                        }
                    }
                } finally {
                    if (!requeried) {
                        synchronized (contacts) {
                            survey_complete = true;
                        }
                        if (DEBUG_SURVEY) {
                            System.out.println("survey complete: nodes=" + id_map.size());
                        }
                        processSurvey(my_id, applicable_keys, id_map);
                        processing[0] = true;
                    }
                }
            }
        });
    } catch (Throwable e) {
        if (!processing[0]) {
            logger.log("Survey complete - no applicable nodes");
            survey_in_progress = false;
        }
    }
}
Also used : DHTTransportContact(com.biglybt.core.dht.transport.DHTTransportContact)

Example 10 with DHTTransportContact

use of com.biglybt.core.dht.transport.DHTTransportContact in project BiglyBT by BiglySoftware.

the class DHTDBImpl method doQuery.

protected void doQuery(final byte[] survey_my_id, final int total, final Map<DHTDBMapping, List<DHTTransportContact>> mapping_to_node_map, final LinkedList<Map.Entry<DHTTransportContact, ByteArrayHashMap<List<DHTDBMapping>>>> to_do, final Map<DHTTransportContact, Object[]> replies, DHTTransportContact done_contact, List<DHTDBMapping> done_mappings, List<byte[]> done_reply) {
    Map.Entry<DHTTransportContact, ByteArrayHashMap<List<DHTDBMapping>>> entry;
    synchronized (to_do) {
        if (done_contact != null) {
            replies.put(done_contact, new Object[] { done_mappings, done_reply });
        }
        if (to_do.size() == 0) {
            if (replies.size() == total) {
                queriesComplete(survey_my_id, mapping_to_node_map, replies);
            }
            return;
        }
        entry = to_do.removeFirst();
    }
    DHTTransportContact contact = entry.getKey();
    boolean handled = false;
    try {
        if (contact.getProtocolVersion() >= DHTTransportUDP.PROTOCOL_VERSION_REPLICATION_CONTROL3) {
            if (DEBUG_SURVEY) {
                System.out.println("Hitting " + contact.getString());
            }
            final List<DHTDBMapping> mapping_list = new ArrayList<>();
            ByteArrayHashMap<List<DHTDBMapping>> map = entry.getValue();
            List<byte[]> prefixes = map.keys();
            List<Object[]> encoded = new ArrayList<>(prefixes.size());
            try {
                this_mon.enter();
                SurveyContactState contact_state = survey_state.get(new HashWrapper(contact.getID()));
                for (byte[] prefix : prefixes) {
                    int prefix_len = prefix.length;
                    int suffix_len = QUERY_STORE_REQUEST_ENTRY_SIZE - prefix_len;
                    List<DHTDBMapping> mappings = map.get(prefix);
                    List<byte[]> l = new ArrayList<>(mappings.size());
                    encoded.add(new Object[] { prefix, l });
                    for (DHTDBMapping m : mappings) {
                        if (contact_state != null) {
                            if (contact_state.testMapping(m)) {
                                if (DEBUG_SURVEY) {
                                    System.out.println("    skipping " + ByteFormatter.encodeString(m.getKey().getBytes()) + " as contact already has");
                                }
                                continue;
                            }
                        }
                        mapping_list.add(m);
                        byte[] k = m.getKey().getBytes();
                        byte[] suffix = new byte[suffix_len];
                        System.arraycopy(k, prefix_len, suffix, 0, suffix_len);
                        l.add(suffix);
                    }
                }
                if (Arrays.equals(contact.getID(), survey_my_id)) {
                    Debug.out("inconsistent - we shouldn't query ourselves!");
                }
                contact.sendQueryStore(new DHTTransportReplyHandlerAdapter() {

                    @Override
                    public void queryStoreReply(DHTTransportContact contact, List<byte[]> response) {
                        try {
                            if (DEBUG_SURVEY) {
                                System.out.println("response " + response.size());
                                for (int i = 0; i < response.size(); i++) {
                                    System.out.println("    " + ByteFormatter.encodeString(response.get(i)));
                                }
                            }
                        } finally {
                            doQuery(survey_my_id, total, mapping_to_node_map, to_do, replies, contact, mapping_list, response);
                        }
                    }

                    @Override
                    public void failed(DHTTransportContact contact, Throwable error) {
                        try {
                            if (DEBUG_SURVEY) {
                                System.out.println("Failed: " + Debug.getNestedExceptionMessage(error));
                            }
                        } finally {
                            doQuery(survey_my_id, total, mapping_to_node_map, to_do, replies, contact, mapping_list, null);
                        }
                    }
                }, QUERY_STORE_REQUEST_ENTRY_SIZE, encoded);
                handled = true;
            } finally {
                this_mon.exit();
            }
        } else {
            if (DEBUG_SURVEY) {
                System.out.println("Not hitting " + contact.getString());
            }
        }
    } finally {
        if (!handled) {
            final List<DHTDBMapping> mapping_list = new ArrayList<>();
            ByteArrayHashMap<List<DHTDBMapping>> map = entry.getValue();
            List<byte[]> prefixes = map.keys();
            for (byte[] prefix : prefixes) {
                mapping_list.addAll(map.get(prefix));
            }
            doQuery(survey_my_id, total, mapping_to_node_map, to_do, replies, contact, mapping_list, null);
        }
    }
}
Also used : DHTTransportContact(com.biglybt.core.dht.transport.DHTTransportContact) DHTTransportReplyHandlerAdapter(com.biglybt.core.dht.transport.DHTTransportReplyHandlerAdapter)

Aggregations

DHTTransportContact (com.biglybt.core.dht.transport.DHTTransportContact)16 InetSocketAddress (java.net.InetSocketAddress)5 DHT (com.biglybt.core.dht.DHT)4 DHTNATPuncher (com.biglybt.core.dht.nat.DHTNATPuncher)4 DHTTransportReplyHandlerAdapter (com.biglybt.core.dht.transport.DHTTransportReplyHandlerAdapter)3 DHTTransportValue (com.biglybt.core.dht.transport.DHTTransportValue)2 HashWrapper (com.biglybt.core.util.HashWrapper)2 BloomFilter (com.biglybt.core.util.bloom.BloomFilter)2 PluginInterface (com.biglybt.pif.PluginInterface)2 DHTPlugin (com.biglybt.plugin.dht.DHTPlugin)2 Map (java.util.Map)2 DHTLogger (com.biglybt.core.dht.DHTLogger)1 DHTControlActivity (com.biglybt.core.dht.control.DHTControlActivity)1 DHTControlContact (com.biglybt.core.dht.control.DHTControlContact)1 DHTNATPuncherListener (com.biglybt.core.dht.nat.DHTNATPuncherListener)1 DHTRouterContact (com.biglybt.core.dht.router.DHTRouterContact)1 DHTTransportFullStats (com.biglybt.core.dht.transport.DHTTransportFullStats)1 DHTTransportUDP (com.biglybt.core.dht.transport.udp.DHTTransportUDP)1 DHTTransportUDPImpl (com.biglybt.core.dht.transport.udp.impl.DHTTransportUDPImpl)1 NATTraversalHandler (com.biglybt.core.nat.NATTraversalHandler)1