forked from I2P_Developers/i2p.i2p
merge of '5a7bb5cbf6a37b5e282620eeb893459dc3ebe4af'
and 'b11d43f037fd0eb4248f7388e26af31209aaf0a2'
This commit is contained in:
@@ -518,7 +518,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
out.write("</a>\n");
|
||||
}
|
||||
}
|
||||
out.write("</th>\n<th colspan=\"2\" align=\"left\">");
|
||||
out.write("</th>\n<th colspan=\"3\" align=\"left\">");
|
||||
// cycle through sort by name or type
|
||||
boolean isTypeSort = false;
|
||||
if (showSort) {
|
||||
@@ -710,7 +710,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
|
||||
if (total == 0) {
|
||||
out.write("<tr class=\"snarkTorrentNoneLoaded\">" +
|
||||
"<td colspan=\"11\">");
|
||||
"<td colspan=\"12\">");
|
||||
synchronized(this) {
|
||||
File dd = _resourceBase;
|
||||
if (!dd.exists() && !dd.mkdirs()) {
|
||||
@@ -728,7 +728,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
out.write("</td></tr>\n");
|
||||
} else /** if (snarks.size() > 1) */ {
|
||||
out.write("<tfoot><tr>\n" +
|
||||
" <th id=\"snarkTorrentTotals\" align=\"left\" colspan=\"6\">");
|
||||
" <th id=\"snarkTorrentTotals\" align=\"left\" colspan=\"7\">");
|
||||
out.write("<span id=\"totals\">");
|
||||
out.write(_t("Totals"));
|
||||
out.write(": ");
|
||||
@@ -774,7 +774,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
if (dht != null) {
|
||||
if (showDebug) {
|
||||
out.write("</tr>\n<tr class=\"dhtDebug\">" +
|
||||
"<th colspan=\"11\">" +
|
||||
"<th colspan=\"12\">" +
|
||||
"<div id=\"dhtDebugPanel\">" +
|
||||
"<input class=\"toggle_input\" id=\"toggle_debug\" type=\"checkbox\"><label class=\"toggleview\" for=\"toggle_debug\">");
|
||||
out.write(toThemeImg("debug"));
|
||||
@@ -1703,10 +1703,10 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
|
||||
out.write("<tr class=\"" + rowClass + "\" id=\"" + b64Short + "\">" +
|
||||
"<td class=\"snarkGraphicStatus\" align=\"center\">");
|
||||
out.write(statusString + "</td>\n\t");
|
||||
out.write(statusString);
|
||||
|
||||
// (i) icon column
|
||||
out.write("<td class=\"snarkTrackerDetails\">");
|
||||
out.write("</td>\n<td class=\"snarkTrackerDetails\">");
|
||||
if (isValid) {
|
||||
String announce = meta.getAnnounce();
|
||||
if (announce == null)
|
||||
@@ -1747,6 +1747,21 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
out.write(toImg(icon));
|
||||
}
|
||||
|
||||
// Comment icon column
|
||||
out.write("</td>\n<td class=\"snarkCommentDetails\">");
|
||||
if (isValid) {
|
||||
CommentSet comments = snark.getComments();
|
||||
if (comments != null && !comments.isEmpty()) {
|
||||
StringBuilder buf = new StringBuilder(128);
|
||||
buf.append("<a href=\"").append(encodedBaseName)
|
||||
.append("/#snarkCommentSection\" title=\"").append(_t("Comments"))
|
||||
.append("\">");
|
||||
toThemeImg(buf, "comment", "", "");
|
||||
buf.append("</a>");
|
||||
out.write(buf.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Torrent name column
|
||||
out.write("</td><td class=\"snarkTorrentName\">");
|
||||
// No need for javascript here.. css now handles this
|
||||
@@ -1912,7 +1927,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
continue;
|
||||
out.write("<tr class=\"peerinfo " + rowClass + "\"><td class=\"snarkGraphicStatus\" title=\"");
|
||||
out.write(_t("Peer attached to swarm"));
|
||||
out.write("\"></td><td colspan=\"4\">");
|
||||
out.write("\"></td><td colspan=\"5\">");
|
||||
PeerID pid = peer.getPeerID();
|
||||
String ch = pid != null ? pid.toString().substring(0, 4) : "????";
|
||||
String client;
|
||||
@@ -2010,7 +2025,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
"<td class=\"snarkTorrentAction\">" +
|
||||
"</td></tr>\n\t");
|
||||
if (showDebug)
|
||||
out.write("<tr class=\"debuginfo " + rowClass + "\"><td class=\"snarkGraphicStatus\"></td><td colspan=\"10\">" + peer.getSocket() + "</td></tr>");
|
||||
out.write("<tr class=\"debuginfo " + rowClass + "\"><td class=\"snarkGraphicStatus\"></td><td colspan=\"11\">" + peer.getSocket() + "</td></tr>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@ import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
91
core/java/src/net/i2p/util/TryCache.java
Normal file
91
core/java/src/net/i2p/util/TryCache.java
Normal file
@@ -0,0 +1,91 @@
|
||||
package net.i2p.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* An object cache which is safe to use by multiple threads without blocking.
|
||||
*
|
||||
* @author zab
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class TryCache<T> {
|
||||
|
||||
/**
|
||||
* Something that creates objects of the type cached by this cache
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public static interface ObjectFactory<T> {
|
||||
T newInstance();
|
||||
}
|
||||
|
||||
private final ObjectFactory<T> factory;
|
||||
private final int capacity;
|
||||
private final List<T> items;
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* @param factory to be used for creating new instances
|
||||
* @param capacity cache up to this many items
|
||||
*/
|
||||
public TryCache(ObjectFactory<T> factory, int capacity) {
|
||||
this.factory = factory;
|
||||
this.capacity = capacity;
|
||||
this.items = new ArrayList<>(capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a cached or newly created item from this cache
|
||||
*/
|
||||
public T acquire() {
|
||||
T rv = null;
|
||||
if (lock.tryLock()) {
|
||||
try {
|
||||
if (!items.isEmpty()) {
|
||||
rv = items.remove(items.size() - 1);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
if (rv == null) {
|
||||
rv = factory.newInstance();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to return this item to the cache but it may fail if
|
||||
* the cache has reached capacity or it's lock is held by
|
||||
* another thread.
|
||||
*/
|
||||
public void release(T item) {
|
||||
if (lock.tryLock()) {
|
||||
try {
|
||||
if (items.size() < capacity) {
|
||||
items.add(item);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all cached items. This is the only method
|
||||
* that blocks until it acquires the lock.
|
||||
*/
|
||||
public void clear() {
|
||||
lock.lock();
|
||||
try {
|
||||
items.clear();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
history.txt
15
history.txt
@@ -1,3 +1,18 @@
|
||||
2018-07-08 zzz
|
||||
* i2psnark: Add comment icon (ticket #2278)
|
||||
* NTCP2: Avoid possible NPEs (ticket #2286)
|
||||
* Transport: More efficient caching (ticket #2263)
|
||||
|
||||
2018-07-06 zzz
|
||||
* NTCP: Read all available data when able (ticket #2243)
|
||||
* SSU: Change remaining acks from List to Set (ticket #2258)
|
||||
|
||||
2018-07-05 zzz
|
||||
* i2psnark:
|
||||
- Fix IOOBE when stopping torrent that is allocating (ticket #2273)
|
||||
- Fix comments wrapping (ticket #2284)
|
||||
* NTCP2: Increase max message size
|
||||
|
||||
2018-07-04 zzz
|
||||
* NTCP: Don't advertise interface address when configured for force-firewalled
|
||||
|
||||
|
||||
@@ -335,7 +335,7 @@ body.iframed {
|
||||
margin-top: -1px !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails, .snarkTorrentDetails {
|
||||
.snarkTrackerDetails, .snarkTorrentDetails, .snarkCommentDetails {
|
||||
width: 16px !important;
|
||||
text-align: center !important;
|
||||
font-weight: bold;
|
||||
@@ -343,13 +343,14 @@ body.iframed {
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkDirInfo td:first-child img {
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkCommentDetails img, .snarkDirInfo td:first-child img {
|
||||
padding: 3px !important;
|
||||
border: 1px solid transparent !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails a:hover img, .snarkTrackerDetails a:focus img,
|
||||
.snarkTorrentDetails a:hover img, .snarkTorrentDetails a:focus img,
|
||||
.snarkCommentDetails a:hover img, .snarkCommentDetails a:focus img,
|
||||
.snarkDirInfo td:first-child a:hover img, .snarkDirInfo td:first-child a:focus img {
|
||||
border: 1px solid #f60 !important;
|
||||
border-radius: 2px;
|
||||
@@ -358,7 +359,7 @@ body.iframed {
|
||||
filter: none !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkDirInfo td:first-child a:active img {
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkCommentDetails a:active img, .snarkDirInfo td:first-child a:active img {
|
||||
box-shadow: inset 2px 2px 2px #337;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
@@ -2842,7 +2843,7 @@ th.snarkTorrentStatus a img, .snarkTorrentETA a img, .snarkTrackerDetails a img,
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
.snarkTorrentDetails {
|
||||
.snarkCommentDetails {
|
||||
padding-left: 10px !important;
|
||||
padding-right: 5px !important;
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ tfoot th {
|
||||
font-size: 8pt !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails, .snarkTorrentDetails {
|
||||
.snarkTrackerDetails, .snarkTorrentDetails, .snarkCommentDetails {
|
||||
width: 16px !important;
|
||||
text-align: center !important;
|
||||
font-weight: bold;
|
||||
@@ -467,7 +467,7 @@ tfoot th {
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkDirInfo td:first-child img {
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkCommentDetails img, .snarkDirInfo td:first-child img {
|
||||
padding: 3px !important;
|
||||
border: 1px solid transparent !important;
|
||||
margin: 0 !important;
|
||||
@@ -484,6 +484,7 @@ tfoot th {
|
||||
|
||||
.snarkTrackerDetails a:hover img, .snarkTrackerDetails a:focus img,
|
||||
.snarkTorrentDetails a:hover img, .snarkTorrentDetails a:focus img,
|
||||
.snarkCommentDetails a:hover img, .snarkCommentDetails a:focus img,
|
||||
.snarkDirInfo td:first-child a:hover img, .snarkDirInfo td:first-child a:focus img {
|
||||
border: 1px solid #f60 !important;
|
||||
border-radius: 2px;
|
||||
@@ -493,7 +494,7 @@ tfoot th {
|
||||
filter: none !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkDirInfo td:first-child a:active img {
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkCommentDetails a:active img, .snarkDirInfo td:first-child a:active img {
|
||||
border: 1px solid #f90 !important;
|
||||
box-shadow: inset 2px 2px 3px 3px #000;
|
||||
transform: scale(0.9);
|
||||
@@ -2882,7 +2883,7 @@ textarea[name="i2cpOpts"] {
|
||||
margin: 1px 2px !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails, .SnarkTorrentDetails {
|
||||
.snarkTrackerDetails, .SnarkTorrentDetails, .snarkCommentDetails {
|
||||
width: 1% !important;
|
||||
}
|
||||
|
||||
@@ -3009,7 +3010,7 @@ th.snarkTorrentStatus a img, .snarkTorrentETA a img, .snarkTrackerDetails a img,
|
||||
padding: 1px 0;
|
||||
}
|
||||
|
||||
.snarkTorrentDetails {
|
||||
.snarkCommentDetails {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
@@ -3023,7 +3024,7 @@ th.snarkTorrentStatus a img, .snarkTorrentETA a img, .snarkTrackerDetails a img,
|
||||
color: transparent !important;
|
||||
}
|
||||
|
||||
.snarkTorrentDetails {
|
||||
.snarkCommentDetails {
|
||||
padding-left: 3px !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -487,7 +487,11 @@ tfoot th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.snarkTorrents thead th:nth-child(3), .snarkTorrents thead th:nth-child(7) {
|
||||
.snarkTorrents thead th:nth-child(3) {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.snarkTorrents thead th:nth-child(7) {
|
||||
text-align: right !important;
|
||||
}
|
||||
|
||||
@@ -553,7 +557,7 @@ th.snarkGraphicStatus, th.snarkTorrentStatus {
|
||||
color: #f60;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails, .snarkTorrentDetails {
|
||||
.snarkTrackerDetails, .snarkTorrentDetails, .snarkCommentDetails {
|
||||
width: 16px !important;
|
||||
text-align: center !important;
|
||||
font-weight: bold;
|
||||
@@ -561,7 +565,7 @@ th.snarkGraphicStatus, th.snarkTorrentStatus {
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkDirInfo td:first-child img {
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkCommentDetails img, .snarkDirInfo td:first-child img {
|
||||
margin: 0;
|
||||
padding: 3px !important;
|
||||
max-width: 16px;
|
||||
@@ -571,6 +575,7 @@ th.snarkGraphicStatus, th.snarkTorrentStatus {
|
||||
|
||||
.snarkTrackerDetails a:hover img, .snarkTrackerDetails a:focus img,
|
||||
.snarkTorrentDetails a:hover img, .snarkTorrentDetails a:focus img,
|
||||
.snarkCommentDetails a:hover img, .snarkCommentDetails a:focus img,
|
||||
.snarkDirInfo td:first-child a:hover img, .snarkDirInfo td:first-child a:focus img {
|
||||
border: 1px solid #f60 !important;
|
||||
border-radius: 2px;
|
||||
@@ -580,7 +585,7 @@ th.snarkGraphicStatus, th.snarkTorrentStatus {
|
||||
mix-blend-mode: normal;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkDirInfo td:first-child a:active img {
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkCommentDetails a:active img, .snarkDirInfo td:first-child a:active img {
|
||||
box-shadow: inset 2px 2px 2px #99f;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
@@ -2382,7 +2387,7 @@ _:-ms-lang(x), *, *:hover, *:focus, input, input:hover, input:focus, a:hover, a:
|
||||
display: none;
|
||||
}
|
||||
|
||||
.snarkGraphicStatus img, .snarkTrackerDetails img, .snarkTorrentDetails img {
|
||||
.snarkGraphicStatus img, .snarkTrackerDetails img, .snarkTorrentDetails img, .snarkCommentDetails img {
|
||||
max-height: 14px !important;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ tfoot tr:nth-child(n+1) {
|
||||
}
|
||||
|
||||
.snarkTorrents thead th:nth-child(3) {
|
||||
text-align: right;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.snarkTorrents th:empty + th:empty, .snarkTorrents td:empty + td:empty, .snarkTorrents th:last-child:empty, .snarkTorrents td:last-child:empty {
|
||||
@@ -494,7 +494,7 @@ th.snarkTorrentStatus {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails, .snarkTorrentDetails {
|
||||
.snarkTrackerDetails, .snarkTorrentDetails, .snarkCommentDetails {
|
||||
width: 16px !important;
|
||||
text-align: center !important;
|
||||
font-weight: bold;
|
||||
@@ -502,7 +502,7 @@ th.snarkTorrentStatus {
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkDirInfo td:first-child img {
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkCommentDetails img, .snarkDirInfo td:first-child img {
|
||||
padding: 3px !important;
|
||||
border: 1px solid transparent !important;
|
||||
margin: 0 !important;
|
||||
@@ -514,6 +514,7 @@ th.snarkTorrentStatus {
|
||||
|
||||
.snarkTrackerDetails a:hover img, .snarkTrackerDetails img:hover, .snarkTrackerDetails a:focus img,
|
||||
.snarkTorrentDetails a:hover img, .snarkTorrentDetails img:hover, .snarkTorrentDetails a:focus img,
|
||||
.snarkCommentDetails a:hover img, .snarkCommentDetails img:hover, .snarkCommentDetails a:focus img,
|
||||
.snarkDirInfo td:first-child a:hover img, .snarkDirInfo td:first-child a:focus img {
|
||||
border: 1px solid #652787 !important;
|
||||
border-radius: 2px;
|
||||
@@ -523,7 +524,7 @@ th.snarkTorrentStatus {
|
||||
filter: none !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkDirInfo td:first-child a:active img {
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkCommentDetails a:active img, .snarkDirInfo td:first-child a:active img {
|
||||
border: 1px solid #f90 !important;
|
||||
box-shadow: inset 2px 2px 3px 3px #000;
|
||||
transform: scale(0.9);
|
||||
|
||||
@@ -478,7 +478,7 @@ th.snarkTorrentStatus {
|
||||
margin-right: 3px !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails, .SnarkTorrentDetails {
|
||||
.snarkTrackerDetails, .SnarkTorrentDetails, .snarkCommentDetails {
|
||||
width: 1%;
|
||||
padding: 2px 0;
|
||||
}
|
||||
@@ -656,7 +656,7 @@ td:first-child {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails, .snarkTorrentDetails {
|
||||
.snarkTrackerDetails, .snarkTorrentDetails, .snarkCommentDetails {
|
||||
width: 16px !important;
|
||||
text-align: center !important;
|
||||
font-weight: bold;
|
||||
@@ -664,7 +664,7 @@ td:first-child {
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkDirInfo td:first-child img {
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkCommentDetails img, .snarkDirInfo td:first-child img {
|
||||
padding: 3px !important;
|
||||
margin: 0 1px !important;
|
||||
width: 16px;
|
||||
@@ -674,6 +674,7 @@ td:first-child {
|
||||
|
||||
.snarkTrackerDetails a:hover img, .snarkTrackerDetails a:focus img,
|
||||
.snarkTorrentDetails a:hover img, .snarkTorrentDetails a:focus img,
|
||||
.snarkCommentDetails a:hover img, .snarkCommentDetails a:focus img,
|
||||
.snarkDirInfo td:not(.parentdir):first-child a:hover img, .snarkDirInfo td:not(.parentdir):first-child a:focus img {
|
||||
border: 1px solid #f60 !important;
|
||||
border-radius: 2px;
|
||||
@@ -683,7 +684,7 @@ td:first-child {
|
||||
filter: none !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkDirInfo td:not(.parentdir):first-child a:active img {
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkCommentDetails a:active img, .snarkDirInfo td:not(.parentdir):first-child a:active img {
|
||||
border: 1px solid #212 !important;
|
||||
box-shadow: inset 3px 3px 2px 1px #202;
|
||||
background: #414;
|
||||
@@ -3231,7 +3232,7 @@ th.snarkTorrentStatus a img, .snarkTorrentETA a img, .snarkTrackerDetails a img,
|
||||
max-width: 18px;
|
||||
}
|
||||
|
||||
.snarkTorrentDetails {
|
||||
.snarkCommentDetails {
|
||||
width: 34px !important;
|
||||
text-align: right !important;
|
||||
padding-right: 0 !important;
|
||||
@@ -3249,7 +3250,7 @@ th.snarkTorrentStatus a img, .snarkTorrentETA a img, .snarkTrackerDetails a img,
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.snarkTorrentDetails {
|
||||
.snarkCommentDetails {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
|
||||
@@ -545,7 +545,7 @@ tfoot tr:first-child th {
|
||||
}
|
||||
|
||||
.snarkTorrents thead th:nth-child(3) {
|
||||
text-align: right;
|
||||
text-align: center;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
@@ -591,7 +591,7 @@ th.snarkTorrentStatus {
|
||||
line-height: 110%;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails, .snarkTorrentDetails {
|
||||
.snarkTrackerDetails, .snarkTorrentDetails, .snarkCommentDetails {
|
||||
width: 16px !important;
|
||||
text-align: center !important;
|
||||
font-weight: bold;
|
||||
@@ -599,7 +599,7 @@ th.snarkTorrentStatus {
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkDirInfo td:first-child img {
|
||||
.snarkTrackerDetails img, .snarkTorrentDetails img, .snarkCommentDetails img, .snarkDirInfo td:first-child img {
|
||||
padding: 3px !important;
|
||||
border: 1px solid transparent !important;
|
||||
margin: 0 !important;
|
||||
@@ -611,6 +611,7 @@ th.snarkTorrentStatus {
|
||||
|
||||
.snarkTrackerDetails a:hover img, .snarkTrackerDetails a:focus img,
|
||||
.snarkTorrentDetails a:hover img, .snarkTorrentDetails a:focus img,
|
||||
.snarkCommentDetails a:hover img, .snarkCommentDetails a:focus img,
|
||||
.snarkDirInfo td:first-child a:hover img, .snarkDirInfo td:first-child a:focus img {
|
||||
border: 1px solid #f60 !important;
|
||||
border-radius: 2px;
|
||||
@@ -620,7 +621,7 @@ th.snarkTorrentStatus {
|
||||
filter: none !important;
|
||||
}
|
||||
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkDirInfo td:first-child a:active img {
|
||||
.snarkTrackerDetails a:active img, .snarkTorrentDetails a:active img, .snarkCommentDetails a:active img, .snarkDirInfo td:first-child a:active img {
|
||||
box-shadow: inset 2px 2px 3px 1px #59513b;
|
||||
transform: scale(0.9);
|
||||
transition: none !important;
|
||||
@@ -3120,7 +3121,7 @@ th.snarkTorrentStatus a img, .snarkTorrentETA a img, .snarkTrackerDetails a img
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.snarkTorrentDetails {
|
||||
.snarkCommentDetails {
|
||||
padding-left: 5px !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public class RouterVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = CoreVersion.VERSION;
|
||||
public final static long BUILD = 5;
|
||||
public final static long BUILD = 7;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
||||
@@ -28,6 +28,7 @@ import net.i2p.data.router.RouterIdentity;
|
||||
import net.i2p.router.CommSystemFacade.Status;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.transport.FIFOBandwidthLimiter;
|
||||
import net.i2p.util.TryCache;
|
||||
import net.i2p.util.Addresses;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
import net.i2p.util.I2PThread;
|
||||
@@ -53,7 +54,7 @@ class EventPumper implements Runnable {
|
||||
private final NTCPTransport _transport;
|
||||
private final ObjectCounter<ByteArray> _blockedIPs;
|
||||
private long _expireIdleWriteTime;
|
||||
private boolean _useDirect;
|
||||
private static boolean _useDirect;
|
||||
|
||||
/**
|
||||
* This probably doesn't need to be bigger than the largest typical
|
||||
@@ -63,13 +64,15 @@ class EventPumper implements Runnable {
|
||||
private static final int BUF_SIZE = 8*1024;
|
||||
private static final int MAX_CACHE_SIZE = 64;
|
||||
|
||||
/**
|
||||
* Read buffers. (write buffers use wrap())
|
||||
* Shared if there are multiple routers in the JVM
|
||||
* Note that if the routers have different PROP_DIRECT settings this will have a mix,
|
||||
* so don't do that.
|
||||
*/
|
||||
private static final LinkedBlockingQueue<ByteBuffer> _bufCache = new LinkedBlockingQueue<ByteBuffer>(MAX_CACHE_SIZE);
|
||||
private static class BufferFactory implements TryCache.ObjectFactory<ByteBuffer> {
|
||||
public ByteBuffer newInstance() {
|
||||
if (_useDirect)
|
||||
return ByteBuffer.allocateDirect(BUF_SIZE);
|
||||
else
|
||||
return ByteBuffer.allocate(BUF_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* every few seconds, iterate across all ntcp connections just to make sure
|
||||
@@ -101,6 +104,8 @@ class EventPumper implements Runnable {
|
||||
long maxMemory = SystemVersion.getMaxMemory();
|
||||
MIN_BUFS = (int) Math.max(MIN_MINB, Math.min(MAX_MINB, 1 + (maxMemory / (16*1024*1024))));
|
||||
}
|
||||
|
||||
private static final TryCache<ByteBuffer> _bufferCache = new TryCache<>(new BufferFactory(), MIN_BUFS);
|
||||
|
||||
public EventPumper(RouterContext ctx, NTCPTransport transport) {
|
||||
_context = ctx;
|
||||
@@ -319,13 +324,7 @@ class EventPumper implements Runnable {
|
||||
}
|
||||
|
||||
|
||||
// Clear the cache if the user changes the setting,
|
||||
// so we can test the effect.
|
||||
boolean newUseDirect = _context.getBooleanProperty(PROP_DIRECT);
|
||||
if (_useDirect != newUseDirect) {
|
||||
_useDirect = newUseDirect;
|
||||
_bufCache.clear();
|
||||
}
|
||||
_useDirect = _context.getBooleanProperty(PROP_DIRECT);
|
||||
} catch (RuntimeException re) {
|
||||
_log.error("Error in the event pumper", re);
|
||||
}
|
||||
@@ -363,7 +362,6 @@ class EventPumper implements Runnable {
|
||||
_wantsRead.clear();
|
||||
_wantsRegister.clear();
|
||||
_wantsWrite.clear();
|
||||
_bufCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -461,27 +459,11 @@ class EventPumper implements Runnable {
|
||||
_selector.wakeup();
|
||||
}
|
||||
|
||||
/**
|
||||
* How many to keep in reserve.
|
||||
* Shared if there are multiple routers in the JVM
|
||||
*/
|
||||
private static int _numBufs = MIN_BUFS;
|
||||
private static int __consecutiveExtra;
|
||||
|
||||
/**
|
||||
* High-frequency path in thread.
|
||||
*/
|
||||
private ByteBuffer acquireBuf() {
|
||||
ByteBuffer rv = _bufCache.poll();
|
||||
// discard buffer if _useDirect setting changes
|
||||
if (rv == null || rv.isDirect() != _useDirect) {
|
||||
if (_useDirect)
|
||||
rv = ByteBuffer.allocateDirect(BUF_SIZE);
|
||||
else
|
||||
rv = ByteBuffer.allocate(BUF_SIZE);
|
||||
_numBufs++;
|
||||
}
|
||||
return rv;
|
||||
return _bufferCache.acquire();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -496,21 +478,7 @@ class EventPumper implements Runnable {
|
||||
return;
|
||||
}
|
||||
buf.clear();
|
||||
int extra = _bufCache.size();
|
||||
boolean cached = extra < _numBufs;
|
||||
|
||||
// TODO always offer if direct?
|
||||
if (cached) {
|
||||
_bufCache.offer(buf);
|
||||
if (extra > MIN_BUFS) {
|
||||
__consecutiveExtra++;
|
||||
if (__consecutiveExtra >= 20) {
|
||||
if (_numBufs > MIN_BUFS)
|
||||
_numBufs--;
|
||||
__consecutiveExtra = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
_bufferCache.release(buf);
|
||||
}
|
||||
|
||||
private void processAccept(SelectionKey key) {
|
||||
|
||||
@@ -63,8 +63,8 @@ class NTCP2Options {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Padding options: send min/max %: (" + (_sendMin * 100) + ", " + (_sendMax * 100) +
|
||||
") recv min/max %: ( " + (_recvMin * 100) + ", " + (_recvMax * 100) +
|
||||
") dummy send/recv B/s: ( " + _sendDummy + ", " + _recvDummy +
|
||||
") delay send/recv ms: ( " + _sendDelay + ", " + _recvDelay + ')';
|
||||
") recv min/max %: (" + (_recvMin * 100) + ", " + (_recvMax * 100) +
|
||||
") dummy send/recv B/s: (" + _sendDummy + ", " + _recvDummy +
|
||||
") delay send/recv ms: (" + _sendDelay + ", " + _recvDelay + ')';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +186,8 @@ public class NTCPConnection implements Closeable {
|
||||
private static final long NTCP2_FAIL_TIMEOUT = 10*1000;
|
||||
private static final long NTCP2_TERMINATION_CLOSE_DELAY = 50;
|
||||
// don't make combined messages too big, to minimize latency
|
||||
private static final int NTCP2_PREFERRED_PAYLOAD_MAX = 5000;
|
||||
// Tunnel data msgs are 1024 + 4 + 9 + 3 = 1040, allow 5
|
||||
private static final int NTCP2_PREFERRED_PAYLOAD_MAX = 5 * 1040;
|
||||
static final int REASON_UNSPEC = 0;
|
||||
static final int REASON_TERMINATION = 1;
|
||||
static final int REASON_TIMEOUT = 2;
|
||||
@@ -897,34 +898,7 @@ public class NTCPConnection implements Closeable {
|
||||
}
|
||||
int availForPad = BUFFER_SIZE - (size + NTCP2Payload.BLOCK_HEADER_SIZE);
|
||||
if (availForPad > 0) {
|
||||
// what we want to send, calculated in proportion to data size
|
||||
int minSend = (int) (size * _paddingConfig.getSendMin());
|
||||
int maxSend = (int) (size * _paddingConfig.getSendMax());
|
||||
// the absolute min and max we can send
|
||||
int min = Math.min(minSend, availForPad);
|
||||
int max = Math.min(maxSend, availForPad);
|
||||
int range = max - min;
|
||||
if (range < MIN_PADDING_RANGE) {
|
||||
// reduce min to enforce minimum range if possible
|
||||
min = Math.max(0, min - (MIN_PADDING_RANGE - range));
|
||||
range = max - min;
|
||||
} else if (range > MAX_PADDING_RANGE) {
|
||||
// Don't send too much, no matter what the config says
|
||||
range = MAX_PADDING_RANGE;
|
||||
}
|
||||
int padlen = min;
|
||||
if (range > 0)
|
||||
padlen += _context.random().nextInt(1 + range);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Padding params:" +
|
||||
" data size: " + size +
|
||||
" avail: " + availForPad +
|
||||
" minSend: " + minSend +
|
||||
" maxSend: " + maxSend +
|
||||
" min: " + min +
|
||||
" max: " + max +
|
||||
" range: " + range +
|
||||
" padlen: " + padlen);
|
||||
int padlen = getPaddingSize(size, availForPad);
|
||||
// all zeros is fine here
|
||||
//Block block = new NTCP2Payload.PaddingBlock(_context, padlen);
|
||||
Block block = new NTCP2Payload.PaddingBlock(padlen);
|
||||
@@ -934,13 +908,57 @@ public class NTCPConnection implements Closeable {
|
||||
sendNTCP2(buf.unencrypted, blocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* NTCP2 only
|
||||
*
|
||||
* @param dataSize the total size of the data we are sending
|
||||
* @param availForPad the available size for padding, not including padding block header,
|
||||
* must be greater than zero
|
||||
* @return min 0 max availForPad
|
||||
* @since 0.9.36
|
||||
*/
|
||||
private int getPaddingSize(int dataSize, int availForPad) {
|
||||
// what we want to send, calculated in proportion to data size
|
||||
int minSend = (int) (dataSize * _paddingConfig.getSendMin());
|
||||
int maxSend = (int) (dataSize * _paddingConfig.getSendMax());
|
||||
// the absolute min and max we can send
|
||||
int min = Math.min(minSend, availForPad);
|
||||
int max = Math.min(maxSend, availForPad);
|
||||
int range = max - min;
|
||||
if (range < MIN_PADDING_RANGE) {
|
||||
// reduce min to enforce minimum range if possible
|
||||
min = Math.max(0, min - (MIN_PADDING_RANGE - range));
|
||||
range = max - min;
|
||||
} else if (range > MAX_PADDING_RANGE) {
|
||||
// Don't send too much, no matter what the config says
|
||||
range = MAX_PADDING_RANGE;
|
||||
}
|
||||
int padlen = min;
|
||||
if (range > 0)
|
||||
padlen += _context.random().nextInt(1 + range);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Padding params:" +
|
||||
" data size: " + dataSize +
|
||||
" avail: " + availForPad +
|
||||
" minSend: " + minSend +
|
||||
" maxSend: " + maxSend +
|
||||
" min: " + min +
|
||||
" max: " + max +
|
||||
" range: " + range +
|
||||
" padlen: " + padlen);
|
||||
return padlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* NTCP2 only
|
||||
*
|
||||
* @since 0.9.36
|
||||
*/
|
||||
private void sendOurRouterInfo(boolean shouldFlood) {
|
||||
sendRouterInfo(_context.router().getRouterInfo(), shouldFlood);
|
||||
RouterInfo ri = _context.router().getRouterInfo();
|
||||
if (ri == null)
|
||||
return;
|
||||
sendRouterInfo(ri, shouldFlood);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -953,18 +971,27 @@ public class NTCPConnection implements Closeable {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Sending router info for: " + ri.getHash() + " flood? " + shouldFlood);
|
||||
List<Block> blocks = new ArrayList<Block>(2);
|
||||
int plen = 2;
|
||||
Block block = new NTCP2Payload.RIBlock(ri, shouldFlood);
|
||||
plen += block.getTotalLength();
|
||||
int size = block.getTotalLength();
|
||||
if (size > BUFFER_SIZE) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("RI too big: " + ri);
|
||||
return;
|
||||
}
|
||||
blocks.add(block);
|
||||
int padlen = 1 + _context.random().nextInt(PADDING_MAX);
|
||||
// all zeros is fine here
|
||||
//block = new NTCP2Payload.PaddingBlock(_context, padlen);
|
||||
block = new NTCP2Payload.PaddingBlock(padlen);
|
||||
plen += block.getTotalLength();
|
||||
blocks.add(block);
|
||||
byte[] tmp = new byte[plen];
|
||||
sendNTCP2(tmp, blocks);
|
||||
int availForPad = BUFFER_SIZE - (size + NTCP2Payload.BLOCK_HEADER_SIZE);
|
||||
if (availForPad > 0) {
|
||||
int padlen = getPaddingSize(size, availForPad);
|
||||
// all zeros is fine here
|
||||
//block = new NTCP2Payload.PaddingBlock(_context, padlen);
|
||||
block = new NTCP2Payload.PaddingBlock(padlen);
|
||||
size += block.getTotalLength();
|
||||
blocks.add(block);
|
||||
}
|
||||
// use a "read buf" for the temp array
|
||||
ByteArray dataBuf = acquireReadBuf();
|
||||
sendNTCP2(dataBuf.getData(), blocks);
|
||||
releaseReadBuf(dataBuf);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -978,18 +1005,21 @@ public class NTCPConnection implements Closeable {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Sending termination, reason: " + reason + ", vaild frames rcvd: " + validFramesRcvd);
|
||||
List<Block> blocks = new ArrayList<Block>(2);
|
||||
int plen = 2;
|
||||
Block block = new NTCP2Payload.TerminationBlock(reason, validFramesRcvd);
|
||||
plen += block.getTotalLength();
|
||||
int plen = block.getTotalLength();
|
||||
blocks.add(block);
|
||||
int padlen = 1 + _context.random().nextInt(PADDING_MAX);
|
||||
// all zeros is fine here
|
||||
//block = new NTCP2Payload.PaddingBlock(_context, padlen);
|
||||
block = new NTCP2Payload.PaddingBlock(padlen);
|
||||
plen += block.getTotalLength();
|
||||
blocks.add(block);
|
||||
byte[] tmp = new byte[plen];
|
||||
sendNTCP2(tmp, blocks);
|
||||
int padlen = getPaddingSize(plen, PADDING_MAX);
|
||||
if (padlen > 0) {
|
||||
// all zeros is fine here
|
||||
//block = new NTCP2Payload.PaddingBlock(_context, padlen);
|
||||
block = new NTCP2Payload.PaddingBlock(padlen);
|
||||
plen += block.getTotalLength();
|
||||
blocks.add(block);
|
||||
}
|
||||
// use a "read buf" for the temp array
|
||||
ByteArray dataBuf = acquireReadBuf();
|
||||
sendNTCP2(dataBuf.getData(), blocks);
|
||||
releaseReadBuf(dataBuf);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -998,10 +1028,15 @@ public class NTCPConnection implements Closeable {
|
||||
* passes it to the pumper for writing.
|
||||
*
|
||||
* @param tmp to be used for output of NTCP2Payload.writePayload(),
|
||||
* must have room for 2 byte length and block output
|
||||
* must have room for block output. May be released immediately on return.
|
||||
* @since 0.9.36
|
||||
*/
|
||||
private synchronized void sendNTCP2(byte[] tmp, List<Block> blocks) {
|
||||
if (_sender == null) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("sender gone", new Exception());
|
||||
return;
|
||||
}
|
||||
int payloadlen = NTCP2Payload.writePayload(tmp, 0, blocks);
|
||||
int framelen = payloadlen + OutboundNTCP2State.MAC_SIZE;
|
||||
// TODO use a buffer
|
||||
@@ -2039,9 +2074,6 @@ public class NTCPConnection implements Closeable {
|
||||
_transport.messageReceived(msg, _remotePeer, null, timeToRecv, size);
|
||||
_lastReceiveTime = _context.clock().now();
|
||||
_messagesRead.incrementAndGet();
|
||||
// TEST send back. null RI for target, not necesary
|
||||
//if (_context.getBooleanProperty("i2np.ntcp2.loopback"))
|
||||
// send(new OutNetMessage(_context, msg, _context.clock().now() + 10*1000, OutNetMessage.PRIORITY_MY_DATA, null));
|
||||
}
|
||||
|
||||
public void gotOptions(byte[] options, boolean isHandshake) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import net.i2p.data.SessionKey;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.transport.FIFOBandwidthLimiter;
|
||||
import net.i2p.router.util.CDQEntry;
|
||||
import net.i2p.util.TryCache;
|
||||
import net.i2p.util.Addresses;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SystemVersion;
|
||||
@@ -45,8 +46,16 @@ class UDPPacket implements CDQEntry {
|
||||
// private boolean _isInbound;
|
||||
private FIFOBandwidthLimiter.Request _bandwidthRequest;
|
||||
|
||||
private static class PacketFactory implements TryCache.ObjectFactory<UDPPacket> {
|
||||
static RouterContext context;
|
||||
public UDPPacket newInstance() {
|
||||
return new UDPPacket(context);
|
||||
}
|
||||
}
|
||||
|
||||
// Warning - this mixes contexts in a multi-router JVM
|
||||
private static final Queue<UDPPacket> _packetCache;
|
||||
private static final TryCache<UDPPacket> _packetCache;
|
||||
private static final TryCache.ObjectFactory<UDPPacket> _packetFactory;
|
||||
private static final boolean CACHE = true;
|
||||
private static final int MIN_CACHE_SIZE = 64;
|
||||
private static final int MAX_CACHE_SIZE = 256;
|
||||
@@ -54,9 +63,11 @@ class UDPPacket implements CDQEntry {
|
||||
if (CACHE) {
|
||||
long maxMemory = SystemVersion.getMaxMemory();
|
||||
int csize = (int) Math.max(MIN_CACHE_SIZE, Math.min(MAX_CACHE_SIZE, maxMemory / (1024*1024)));
|
||||
_packetCache = new LinkedBlockingQueue<UDPPacket>(csize);
|
||||
_packetFactory = new PacketFactory();
|
||||
_packetCache = new TryCache<>(_packetFactory, csize);
|
||||
} else {
|
||||
_packetCache = null;
|
||||
_packetFactory = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,18 +409,9 @@ class UDPPacket implements CDQEntry {
|
||||
public static UDPPacket acquire(RouterContext ctx, boolean inbound) {
|
||||
UDPPacket rv = null;
|
||||
if (CACHE) {
|
||||
rv = _packetCache.poll();
|
||||
if (rv != null) {
|
||||
synchronized(rv) {
|
||||
if (!rv._released) {
|
||||
Log log = rv._context.logManager().getLog(UDPPacket.class);
|
||||
log.error("Unreleased cached packet", new Exception());
|
||||
rv = null;
|
||||
} else {
|
||||
rv.init(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
PacketFactory.context = ctx;
|
||||
rv = _packetCache.acquire();
|
||||
rv.init(ctx);
|
||||
}
|
||||
if (rv == null)
|
||||
rv = new UDPPacket(ctx);
|
||||
@@ -440,7 +442,7 @@ class UDPPacket implements CDQEntry {
|
||||
}
|
||||
if (!CACHE)
|
||||
return;
|
||||
_packetCache.offer(this);
|
||||
_packetCache.release(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -448,8 +450,10 @@ class UDPPacket implements CDQEntry {
|
||||
* @since 0.9.2
|
||||
*/
|
||||
public static void clearCache() {
|
||||
if (CACHE)
|
||||
if (CACHE) {
|
||||
PacketFactory.context = null;
|
||||
_packetCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void verifyNotReleased() {
|
||||
|
||||
Reference in New Issue
Block a user