use of net.i2p.data.LeaseSet in project i2p.i2p by i2p.
the class NetDbRenderer method renderLeaseSetHTML.
/**
* @param debug @since 0.7.14 sort by distance from us, display
* median distance, and other stuff, useful when floodfill
*/
public void renderLeaseSetHTML(Writer out, boolean debug) throws IOException {
StringBuilder buf = new StringBuilder(4 * 1024);
if (debug)
buf.append("<p id=\"debugmode\">Debug mode - Sorted by hash distance, closest first</p>\n");
Hash ourRKey;
Set<LeaseSet> leases;
DecimalFormat fmt;
if (debug) {
ourRKey = _context.routerHash();
leases = new TreeSet<LeaseSet>(new LeaseSetRoutingKeyComparator(ourRKey));
fmt = new DecimalFormat("#0.00");
} else {
ourRKey = null;
leases = new TreeSet<LeaseSet>(new LeaseSetComparator());
fmt = null;
}
leases.addAll(_context.netDb().getLeases());
int medianCount = 0;
int rapCount = 0;
BigInteger median = null;
int c = 0;
// Summary
FloodfillNetworkDatabaseFacade netdb = (FloodfillNetworkDatabaseFacade) _context.netDb();
if (debug) {
buf.append("<table id=\"leasesetdebug\">\n");
} else {
buf.append("<table id=\"leasesetsummary\">\n");
}
buf.append("<tr><th colspan=\"3\">Leaseset Summary</th>").append("<th><a href=\"/configadvanced\" title=\"").append(_t("Manually Configure Floodfill Participation")).append("\">[").append(_t("Configure Floodfill Participation")).append("]</a></th></tr>\n").append("<tr><td><b>Total Leasesets:</b></td><td colspan=\"3\">").append(leases.size()).append("</td></tr>\n");
if (debug) {
buf.append("<tr><td><b>Published (RAP) Leasesets:</b></td><td colspan=\"3\">").append(netdb.getKnownLeaseSets()).append("</td></tr>\n").append("<tr><td><b>Mod Data:</b></td><td>").append(DataHelper.getUTF8(_context.routerKeyGenerator().getModData())).append("</td>").append("<td><b>Last Changed:</b></td><td>").append(new Date(_context.routerKeyGenerator().getLastChanged())).append("</td></tr>\n").append("<tr><td><b>Next Mod Data:</b></td><td>").append(DataHelper.getUTF8(_context.routerKeyGenerator().getNextModData())).append("</td>").append("<td><b>Change in:</b></td><td>").append(DataHelper.formatDuration(_context.routerKeyGenerator().getTimeTillMidnight())).append("</td></tr>\n");
}
int ff = _context.peerManager().getPeersByCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL).size();
buf.append("<tr><td><b>Known Floodfills:</b></td><td colspan=\"3\">").append(ff).append("</td></tr>\n").append("<tr><td><b>Currently Floodfill?</b></td><td colspan=\"3\">").append(netdb.floodfillEnabled() ? "yes" : "no").append("</td></tr>\n");
buf.append("</table>\n");
if (leases.isEmpty()) {
if (!debug)
buf.append("<div id=\"noleasesets\"><i>").append(_t("No Leasesets currently active.")).append("</i></div>");
} else {
if (debug) {
// Find the center of the RAP leasesets
for (LeaseSet ls : leases) {
if (ls.getReceivedAsPublished())
rapCount++;
}
medianCount = rapCount / 2;
}
boolean linkSusi = WebAppStarter.isWebAppRunning("susidns");
long now = _context.clock().now();
buf.append("<div class=\"leasesets_container\">");
for (LeaseSet ls : leases) {
Destination dest = ls.getDestination();
Hash key = dest.calculateHash();
buf.append("<table class=\"leaseset\">\n").append("<tr><th><b>").append(_t("LeaseSet")).append(":</b> <code>").append(key.toBase64()).append("</code>");
if (_context.keyRing().get(key) != null)
buf.append(" (").append(_t("Encrypted")).append(')');
buf.append("</th>");
if (_context.clientManager().isLocal(dest)) {
buf.append("<th><a href=\"tunnels#" + key.toBase64().substring(0, 4) + "\">" + _t("Local") + "</a> ");
boolean unpublished = !_context.clientManager().shouldPublishLeaseSet(key);
if (unpublished)
buf.append("<b>").append(_t("Unpublished")).append("</b> ");
buf.append("<b>").append(_t("Destination")).append(":</b> ");
TunnelPoolSettings in = _context.tunnelManager().getInboundSettings(key);
if (in != null && in.getDestinationNickname() != null)
buf.append(in.getDestinationNickname());
else
buf.append(dest.toBase64().substring(0, 6));
buf.append("</th></tr>\n<tr><td");
// If the dest is published but not in the addressbook, an extra
// <td> is appended with an "Add to addressbook" link, so this
// <td> should not span 2 columns.
String host = null;
if (!unpublished) {
host = _context.namingService().reverseLookup(dest);
}
if (unpublished || host != null || !linkSusi) {
buf.append(" colspan=\"2\"");
}
buf.append(">");
String b32 = dest.toBase32();
buf.append("<a href=\"http://").append(b32).append("\">").append(b32).append("</a></td>");
if (linkSusi && !unpublished) {
if (host == null) {
buf.append("<td class=\"addtobook\" colspan=\"2\">").append("<a title=\"").append(_t("Add to addressbook")).append("\" href=\"/susidns/addressbook.jsp?book=private&destination=").append(dest.toBase64()).append("#add\">").append(_t("Add to local addressbook")).append("</a></td>");
}
}
// else probably a client
} else {
buf.append("<th><b>").append(_t("Destination")).append(":</b> ");
String host = _context.namingService().reverseLookup(dest);
if (host != null) {
buf.append("<a href=\"http://").append(host).append("/\">").append(host).append("</a></th>");
} else {
String b32 = dest.toBase32();
buf.append("<code>").append(dest.toBase64().substring(0, 6)).append("</code></th>").append("</tr>\n<tr><td");
if (!linkSusi)
buf.append(" colspan=\"2\"");
buf.append("><a href=\"http://").append(b32).append("\">").append(b32).append("</a></td>\n");
if (linkSusi) {
buf.append("<td class=\"addtobook\"><a title=\"").append(_t("Add to addressbook")).append("\" href=\"/susidns/addressbook.jsp?book=private&destination=").append(dest.toBase64()).append("#add\">").append(_t("Add to local addressbook")).append("</a></td>");
}
}
}
buf.append("</tr>\n<tr><td colspan=\"2\">\n");
long exp = ls.getLatestLeaseDate() - now;
if (exp > 0)
buf.append("<b>").append(_t("Expires in {0}", DataHelper.formatDuration2(exp))).append("</b>");
else
buf.append("<b>").append(_t("Expired {0} ago", DataHelper.formatDuration2(0 - exp))).append("</b>");
buf.append("</td></tr>\n");
if (debug) {
buf.append("<tr><td colspan=\"2\">");
buf.append("<b>RAP?</b> ").append(ls.getReceivedAsPublished());
buf.append(" <b>RAR?</b> ").append(ls.getReceivedAsReply());
BigInteger dist = HashDistance.getDistance(ourRKey, ls.getRoutingKey());
if (ls.getReceivedAsPublished()) {
if (c++ == medianCount)
median = dist;
}
buf.append(" <b>Distance: </b>").append(fmt.format(biLog2(dist)));
buf.append("</td></tr>\n<tr><td colspan=\"2\">");
// buf.append(dest.toBase32()).append("<br>");
buf.append("<b>Signature type:</b> ").append(dest.getSigningPublicKey().getType());
buf.append(" <b>Encryption Key:</b> ").append(ls.getEncryptionKey().toBase64().substring(0, 20)).append("…");
buf.append("</td></tr>\n<tr><td colspan=\"2\">");
buf.append("<b>Routing Key:</b> ").append(ls.getRoutingKey().toBase64());
buf.append("</td></tr>");
}
buf.append("<tr><td colspan=\"2\"><ul class=\"netdb_leases\">");
for (int i = 0; i < ls.getLeaseCount(); i++) {
Lease lease = ls.getLease(i);
buf.append("<li><b>").append(_t("Lease")).append(' ').append(i + 1).append(":</b> <span class=\"netdb_gateway\" title=\"").append(_t("Gateway")).append("\"><img src=\"themes/console/images/info/gateway.png\" alt=\"").append(_t("Gateway")).append("\"></span> <span class=\"tunnel_peer\">");
buf.append(_context.commSystem().renderPeerHTML(lease.getGateway()));
buf.append("</span> <span class=\"netdb_tunnel\">").append(_t("Tunnel")).append(" <span class=\"tunnel_id\">").append(lease.getTunnelId().getTunnelId()).append("</span></span> ");
if (debug) {
long exl = lease.getEndDate().getTime() - now;
if (exl > 0)
buf.append("<b class=\"netdb_expiry\">").append(_t("Expires in {0}", DataHelper.formatDuration2(exl))).append("</b>");
else
buf.append("<b class=\"netdb_expiry\">").append(_t("Expired {0} ago", DataHelper.formatDuration2(0 - exl))).append("</b>");
}
buf.append("</li>");
}
buf.append("</ul></td></tr>\n");
buf.append("</table>\n");
out.write(buf.toString());
buf.setLength(0);
}
// for each
if (debug) {
buf.append("<table id=\"leasesetdebug\"><tr><td><b>Network data (only valid if floodfill):</b></td><td colspan=\"3\">");
// buf.append("</b></p><p><b>Center of Key Space (router hash): " + ourRKey.toBase64());
if (median != null) {
double log2 = biLog2(median);
buf.append("</td></tr>").append("<tr><td><b>Median distance (bits):</b></td><td colspan=\"3\">").append(fmt.format(log2)).append("</td></tr>\n");
// 2 for 4 floodfills... -1 for median
// this can be way off for unknown reasons
int total = (int) Math.round(Math.pow(2, 2 + 256 - 1 - log2));
buf.append("<tr><td><b>Estimated total floodfills:</b></td><td colspan=\"3\">").append(total).append("</td></tr>\n");
buf.append("<tr><td><b>Estimated total leasesets:</b></td><td colspan=\"3\">").append(total * rapCount / 4);
} else {
buf.append("<i>Not floodfill or no data.</i>");
}
buf.append("</td></tr></table>\n");
}
// median table
buf.append("</div>");
}
// !empty
out.write(buf.toString());
out.flush();
}
use of net.i2p.data.LeaseSet in project i2p.i2p by i2p.
the class SummaryHelper method getDestinations.
/**
* Client destinations connected locally.
*
* @return html section summary
*/
public String getDestinations() {
// convert the set to a list so we can sort by name and not lose duplicates
List<Destination> clients = new ArrayList<Destination>(_context.clientManager().listClients());
StringBuilder buf = new StringBuilder(512);
boolean link = WebAppStarter.isWebAppRunning("i2ptunnel");
buf.append("<h3>");
if (link) {
buf.append("<a href=\"/i2ptunnelmgr\" target=\"_top\" title=\"").append(_t("Add/remove/edit & control your client and server tunnels")).append("\">");
}
buf.append(_t("Local Tunnels"));
if (link) {
buf.append("</a>");
}
buf.append("</h3><hr class=\"b\">");
if (!clients.isEmpty()) {
Collections.sort(clients, new AlphaComparator());
buf.append("<table id=\"sb_localtunnels\">");
for (Destination client : clients) {
String name = getName(client);
Hash h = client.calculateHash();
buf.append("<tr><td align=\"right\"><img src=\"/themes/console/images/");
if (_context.clientManager().shouldPublishLeaseSet(h))
buf.append("server.png\" alt=\"Server\" title=\"").append(_t("Hidden Service")).append("\">");
else
buf.append("client.png\" alt=\"Client\" title=\"").append(_t("Client")).append("\">");
buf.append("</td><td align=\"left\"><b><a href=\"tunnels#").append(h.toBase64().substring(0, 4));
buf.append("\" target=\"_top\" title=\"").append(_t("Show tunnels")).append("\">");
// Increase permitted max length of tunnel name & handle overflow with css
if (name.length() <= 32)
buf.append(DataHelper.escapeHTML(name));
else
buf.append(DataHelper.escapeHTML(ServletUtil.truncate(name, 29))).append("…");
buf.append("</a></b></td>\n");
LeaseSet ls = _context.netDb().lookupLeaseSetLocally(h);
if (ls != null && _context.tunnelManager().getOutboundClientTunnelCount(h) > 0) {
long timeToExpire = ls.getEarliestLeaseDate() - _context.clock().now();
if (timeToExpire < 0) {
// red or yellow light
buf.append("<td><img src=\"/themes/console/images/local_inprogress.png\" alt=\"").append(_t("Rebuilding")).append("…\" title=\"").append(_t("Leases expired")).append(" ").append(DataHelper.formatDuration2(0 - timeToExpire));
buf.append(" ").append(_t("ago")).append(". ").append(_t("Rebuilding")).append("…\"></td></tr>\n");
} else {
// green light
buf.append("<td><img src=\"/themes/console/images/local_up.png\" alt=\"Ready\" title=\"").append(_t("Ready")).append("\"></td></tr>\n");
}
} else {
// yellow light
buf.append("<td><img src=\"/themes/console/images/local_inprogress.png\" alt=\"").append(_t("Building")).append("…\" title=\"").append(_t("Building tunnels")).append("…\"></td></tr>\n");
}
}
buf.append("</table>");
} else {
buf.append("<center><i>").append(_t("none")).append("</i></center>");
}
return buf.toString();
}
use of net.i2p.data.LeaseSet in project i2p.i2p by i2p.
the class SybilRenderer method renderRouterInfoHTML.
/**
* The whole thing
*
* @param routerPrefix ignored
*/
private void renderRouterInfoHTML(Writer out, String routerPrefix) throws IOException {
Set<Hash> ffs = _context.peerManager().getPeersByCapability('f');
List<RouterInfo> ris = new ArrayList<RouterInfo>(ffs.size());
Hash us = _context.routerHash();
Hash ourRKey = _context.router().getRouterInfo().getRoutingKey();
for (Hash ff : ffs) {
if (ff.equals(us))
continue;
RouterInfo ri = _context.netDb().lookupRouterInfoLocally(ff);
if (ri != null)
ris.add(ri);
}
if (ris.isEmpty()) {
out.write("<h3 class=\"sybils\">No known floodfills</h3>");
return;
}
StringBuilder buf = new StringBuilder(4 * 1024);
buf.append("<p id=\"sybilinfo\"><b>This is an experimental network database tool for debugging and analysis. Do not panic even if you see warnings below. " + "Possible \"threats\" are summarized at the bottom, however these are unlikely to be real threats. " + "If you see anything you would like to discuss with the devs, contact us on IRC #i2p-dev.</b></p>" + "<div id=\"sybilnav\"><ul><li><a href=\"#known\">FF Summary</a>" + "</li><li><a href=\"#family\">Same Family</a>" + "</li><li><a href=\"#ourIP\">IP close to us</a>" + "</li><li><a href=\"#sameIP\">Same IP</a>" + "</li><li><a href=\"#same24\">Same /24</a>" + "</li><li><a href=\"#same16\">Same /16</a>" + "</li><li><a href=\"#pairs\">Pair distance</a>" + "</li><li><a href=\"#ritoday\">Close to us</a>" + "</li><li><a href=\"#ritmrw\">Close to us tomorrow</a>" + "</li><li><a href=\"#dht\">DHT neighbors</a>" + "</li><li><a href=\"#dest\">Close to our destinations</a>" + "</li><li><a href=\"#threats\">Highest threats</a>" + "</li></ul></div>");
renderRouterInfo(buf, _context.router().getRouterInfo(), null, true, false);
buf.append("<h3 id=\"known\" class=\"sybils\">Known Floodfills: ").append(ris.size()).append("</h3>");
double tot = 0;
int count = 200;
byte[] b = new byte[32];
for (int i = 0; i < count; i++) {
_context.random().nextBytes(b);
Hash h = new Hash(b);
double d = closestDistance(h, ris);
tot += d;
}
double avgMinDist = tot / count;
buf.append("<div id=\"sybils_summary\">\n");
buf.append("<b>Average closest floodfill distance:</b> ").append(fmt.format(avgMinDist)).append("<br>\n");
buf.append("<b>Routing Data:</b> \"").append(DataHelper.getUTF8(_context.routerKeyGenerator().getModData())).append("\" <b>Last Changed:</b> ").append(new Date(_context.routerKeyGenerator().getLastChanged())).append("<br>\n");
buf.append("<b>Next Routing Data:</b> \"").append(DataHelper.getUTF8(_context.routerKeyGenerator().getNextModData())).append("\" <b>Rotates in:</b> ").append(DataHelper.formatDuration(_context.routerKeyGenerator().getTimeTillMidnight())).append("\n");
buf.append("</div>\n");
Map<Hash, Points> points = new HashMap<Hash, Points>(64);
// IP analysis
renderIPGroupsFamily(out, buf, ris, points);
renderIPGroupsUs(out, buf, ris, points);
renderIPGroups32(out, buf, ris, points);
renderIPGroups24(out, buf, ris, points);
renderIPGroups16(out, buf, ris, points);
// Pairwise distance analysis
renderPairDistance(out, buf, ris, points);
// Distance to our router analysis
buf.append("<h3 id=\"ritoday\" class=\"sybils\">Closest Floodfills to Our Routing Key (Where we Store our RI)</h3>");
buf.append("<p class=\"sybil_info\"><a href=\"/netdb?caps=f&sybil\">See all</a></p>");
renderRouterInfoHTML(out, buf, ourRKey, avgMinDist, ris, points);
RouterKeyGenerator rkgen = _context.routerKeyGenerator();
Hash nkey = rkgen.getNextRoutingKey(us);
buf.append("<h3 id=\"ritmrw\" class=\"sybils\">Closest Floodfills to Tomorrow's Routing Key (Where we will Store our RI)</h3>");
buf.append("<p class=\"sybil_info\"><a href=\"/netdb?caps=f&sybil\">See all</a></p>");
renderRouterInfoHTML(out, buf, nkey, avgMinDist, ris, points);
buf.append("<h3 id=\"dht\" class=\"sybils\">Closest Floodfills to Our Router Hash (DHT Neighbors if we are Floodfill)</h3>");
renderRouterInfoHTML(out, buf, us, avgMinDist, ris, points);
// Distance to our published destinations analysis
buf.append("<h3 id=\"dest\" class=\"sybils\">Floodfills Close to Our Destinations</h3>");
Map<Hash, TunnelPool> clientInboundPools = _context.tunnelManager().getInboundClientPools();
List<Hash> destinations = new ArrayList<Hash>(clientInboundPools.keySet());
// boolean debug = _context.getBooleanProperty(HelperBase.PROP_ADVANCED);
for (Hash client : destinations) {
boolean isLocal = _context.clientManager().isLocal(client);
if (!isLocal)
continue;
if (!_context.clientManager().shouldPublishLeaseSet(client))
continue;
LeaseSet ls = _context.netDb().lookupLeaseSetLocally(client);
if (ls == null)
continue;
Hash rkey = ls.getRoutingKey();
TunnelPool in = clientInboundPools.get(client);
String name = (in != null) ? in.getSettings().getDestinationNickname() : client.toBase64().substring(0, 4);
buf.append("<h3 class=\"sybils\">Closest floodfills to the Routing Key for " + DataHelper.escapeHTML(name) + " (where we store our LS)</h3>");
buf.append("<p class=\"sybil_info\"><a href=\"/netdb?caps=f&sybil=" + ls.getHash().toBase64() + "\">See all</a></p>");
renderRouterInfoHTML(out, buf, rkey, avgMinDist, ris, points);
nkey = rkgen.getNextRoutingKey(ls.getHash());
buf.append("<h3 class=\"sybils\">Closest floodfills to Tomorrow's Routing Key for " + DataHelper.escapeHTML(name) + " (where we will store our LS)</h3>");
buf.append("<p class=\"sybil_info\"><a href=\"/netdb?caps=f&sybil=" + ls.getHash().toBase64() + "\">See all</a></p>");
renderRouterInfoHTML(out, buf, nkey, avgMinDist, ris, points);
}
// Profile analysis
addProfilePoints(ris, points);
addVersionPoints(ris, points);
if (!points.isEmpty()) {
List<Hash> warns = new ArrayList<Hash>(points.keySet());
Collections.sort(warns, new PointsComparator(points));
buf.append("<h3 id=\"threats\" class=\"sybils\">Routers with Most Threat Points</h3>");
for (Hash h : warns) {
RouterInfo ri = _context.netDb().lookupRouterInfoLocally(h);
if (ri == null)
continue;
Points pp = points.get(h);
double p = pp.points;
if (p < MIN_DISPLAY_POINTS)
// sorted
break;
buf.append("<p class=\"threatpoints\"><b>Threat Points: " + fmt.format(p) + "</b></p><ul>");
for (String s : pp.reasons) {
buf.append("<li>").append(s).append("</li>");
}
buf.append("</ul>");
renderRouterInfo(buf, ri, null, false, false);
}
}
out.write(buf.toString());
out.flush();
buf.setLength(0);
}
use of net.i2p.data.LeaseSet in project i2p.i2p by i2p.
the class RequestLeaseSetMessageHandler method handleMessage.
public void handleMessage(I2CPMessage message, I2PSessionImpl session) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Handle message " + message);
RequestLeaseSetMessage msg = (RequestLeaseSetMessage) message;
LeaseSet leaseSet = new LeaseSet();
for (int i = 0; i < msg.getEndpoints(); i++) {
Lease lease = new Lease();
lease.setGateway(msg.getRouter(i));
lease.setTunnelId(msg.getTunnelId(i));
lease.setEndDate(msg.getEndDate());
// lease.setStartDate(msg.getStartDate());
leaseSet.addLease(lease);
}
signLeaseSet(leaseSet, session);
}
use of net.i2p.data.LeaseSet in project i2p.i2p by i2p.
the class DatabaseStoreMessage method readMessage.
public void readMessage(byte[] data, int offset, int dataSize, int type) throws I2NPMessageException {
if (type != MESSAGE_TYPE)
throw new I2NPMessageException("Message type is incorrect for this message");
int curIndex = offset;
_key = Hash.create(data, curIndex);
// Fast-fail here to save resources.
if (_key.equals(Hash.FAKE_HASH)) {
// createRateStat in KNDF
_context.statManager().addRateData("netDb.DSMAllZeros", 1);
throw new I2NPMessageException("DSM all zeros");
}
curIndex += Hash.HASH_LENGTH;
// as of 0.9.18, ignore other 7 bits of the type byte, in preparation for future options
int dbType = data[curIndex] & 0x01;
curIndex++;
_replyToken = DataHelper.fromLong(data, curIndex, 4);
curIndex += 4;
if (_replyToken > 0) {
long tunnel = DataHelper.fromLong(data, curIndex, 4);
if (tunnel > 0)
_replyTunnel = new TunnelId(tunnel);
curIndex += 4;
_replyGateway = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH;
} else {
_replyTunnel = null;
_replyGateway = null;
}
if (dbType == DatabaseEntry.KEY_TYPE_LEASESET) {
_dbEntry = new LeaseSet();
try {
_dbEntry.readBytes(new ByteArrayInputStream(data, curIndex, data.length - curIndex));
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error reading the leaseSet", dfe);
} catch (IOException ioe) {
throw new I2NPMessageException("Error reading the leaseSet", ioe);
}
} else {
// dbType == DatabaseEntry.KEY_TYPE_ROUTERINFO
_dbEntry = new RouterInfo();
int compressedSize = (int) DataHelper.fromLong(data, curIndex, 2);
curIndex += 2;
if (compressedSize <= 0 || curIndex + compressedSize > data.length || curIndex + compressedSize > dataSize + offset)
throw new I2NPMessageException("Compressed RI length: " + compressedSize + " but remaining bytes: " + Math.min(data.length - curIndex, dataSize + offset - curIndex));
try {
// TODO we could delay decompression, just copy to a new byte array and store in _byteCache
// May not be necessary since the IBGW now uses UnknownI2NPMessage.
// DSMs at the OBEP are generally garlic wrapped, so the OBEP won't see it.
// If we do delay it, getEntry() will have to check if _dbEntry is null and _byteCache
// is non-null, and then decompress.
byte[] decompressed = DataHelper.decompress(data, curIndex, compressedSize);
_dbEntry.readBytes(new ByteArrayInputStream(decompressed));
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error reading the routerInfo", dfe);
} catch (IOException ioe) {
throw new I2NPMessageException("Corrupt compressed routerInfo size = " + compressedSize, ioe);
}
}
// if (!key.equals(_dbEntry.getHash()))
// throw new I2NPMessageException("Hash mismatch in DSM");
}
Aggregations