forked from I2P_Developers/i2p.i2p
Compare commits
212 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 656670919d | |||
| bf99b04e0a | |||
|
|
4191eb98b0 | ||
|
|
1eec4484fd | ||
|
|
dc0c97c0ae | ||
|
|
a71372c679 | ||
|
|
cb2ce5ea29 | ||
|
|
b3f8025393 | ||
|
|
809bb59c9d | ||
|
|
61456ba57e | ||
|
|
d05b02de13 | ||
|
|
a4d270fa63 | ||
|
|
a946af721e | ||
|
|
568f242998 | ||
|
|
9338196c30 | ||
| 90fc3b0e57 | |||
|
|
08de93e7ef | ||
|
|
96593c7287 | ||
|
|
471ddaa209 | ||
|
|
17946fbfab | ||
|
|
22108f2c58 | ||
|
|
2a7bb5b550 | ||
|
|
ae00ec5dd6 | ||
|
|
f9384d627c | ||
|
|
bbb731af6c | ||
|
|
2ea05f01eb | ||
|
|
99405b7dff | ||
| 5a1027c5ed | |||
| 0ed88c5686 | |||
| 32b817f9b1 | |||
| 04d04d0169 | |||
|
|
d4a717e6b6 | ||
|
|
f7df15fd5d | ||
|
|
29dfa77bce | ||
|
|
02fbd7f9d6 | ||
|
|
c453dd0e34 | ||
|
|
8b8a3a4a60 | ||
|
|
8b664fe2a1 | ||
|
|
50a6a81706 | ||
|
|
9944dc0696 | ||
|
|
65387def16 | ||
|
|
19f1f7c380 | ||
|
|
c36aaa62ba | ||
|
|
dc120847e1 | ||
|
|
1aea5b3dec | ||
|
|
9ea41b6e67 | ||
|
|
4a85f30bf4 | ||
|
|
c4445143f9 | ||
|
|
9e2c063465 | ||
|
|
4dd78ed31b | ||
|
|
330f1f341e | ||
| 79bd5f1c11 | |||
| 1ad1883d56 | |||
|
|
4b85c56903 | ||
|
|
7289c89171 | ||
|
|
c6a2e99a0d | ||
|
|
1757a2cc08 | ||
| a51ae64e41 | |||
| fd4e4fbc64 | |||
| 9a63be8f69 | |||
| 212c87ffd8 | |||
|
|
16509e5921 | ||
|
|
4c172760cc | ||
|
|
7330e5fef8 | ||
| 6cfb2baad3 | |||
| 3870924fbd | |||
| a692ab42fa | |||
| 05a290cdd5 | |||
| ea29c961ed | |||
| 4005bd6804 | |||
| e826ce723a | |||
| 6822bf7978 | |||
| e2c3ea3ffc | |||
| 2e51577f39 | |||
|
|
b92ba5edbb | ||
|
|
aeb1d40658 | ||
| bb39d8c6fd | |||
| bb74bc33d1 | |||
| af90121b47 | |||
| f015ce1f0b | |||
|
|
785d184676 | ||
|
|
ca5ed9d1b7 | ||
|
|
8fdc4bc9b0 | ||
|
|
7d2bbaad94 | ||
| ed8197f6d2 | |||
| e0f77731c5 | |||
| 3b51f420c4 | |||
| cd1ed63908 | |||
| a64d0a54b1 | |||
| 1b74b49e0f | |||
| 95cf306526 | |||
| a18197dbdd | |||
| dcb9d38114 | |||
| 544563672c | |||
| 0de6c932f5 | |||
|
|
ba8c8aa90d | ||
|
|
f9cc72e892 | ||
|
|
751134f5df | ||
|
|
4025a57529 | ||
|
|
bad27e648a | ||
| 8ab1892560 | |||
| 6ec1772c82 | |||
| 08a3165c44 | |||
| 5d6edad9d4 | |||
| 01f9be4622 | |||
| 5615b13027 | |||
| cc4158a7e1 | |||
|
|
80ee0a3b54 | ||
|
|
f21b079e25 | ||
|
|
8a4745a465 | ||
|
|
7bd978e569 | ||
| 563e1f97e8 | |||
| fc589db9b2 | |||
| 3309b53401 | |||
| a61183303f | |||
| cd58dfdf99 | |||
| 45f3a35fac | |||
|
|
9919a41436 | ||
|
|
42ea77df7f | ||
| ab4a5d15a1 | |||
| f225c1cca0 | |||
| 6ee162002a | |||
| fefcb6c2cb | |||
| cdcbc80248 | |||
|
|
965b2611b3 | ||
| 443abce647 | |||
|
|
923c3d8b4c | ||
|
|
925f9d0a28 | ||
| 49b11bb49e | |||
| 5d494ba89a | |||
| cd0d062fca | |||
| b3d1a76146 | |||
| 824d5a0d36 | |||
| 34973371ac | |||
| 7ee7cbf660 | |||
| 66f3484508 | |||
| c54b40288b | |||
| ff0c168d65 | |||
| 82e344055b | |||
| 63c6613261 | |||
|
|
15a8d39ef5 | ||
|
|
85629aca86 | ||
|
|
5069bebe99 | ||
|
|
b81ff32434 | ||
|
|
5d2f5c7a1f | ||
|
|
b862d14ecb | ||
|
|
4e3effa7e5 | ||
|
|
a825132961 | ||
|
|
bb637eb757 | ||
|
|
94f8b81bd3 | ||
|
|
1d89e136bd | ||
| 91f1ece753 | |||
|
|
6725ce096c | ||
|
|
a568ad2bbc | ||
|
|
8e72445273 | ||
|
|
3c4994c0e1 | ||
|
|
0802b9a8dc | ||
|
|
ed5c61725a | ||
|
|
4622080e07 | ||
|
|
8d6a12552c | ||
|
|
f8ed3c561e | ||
| 7c8e5c6d66 | |||
| d699eaaec9 | |||
| 60e57ec29e | |||
| 03f58d1886 | |||
| 0bd75f0e56 | |||
| df3fc6e05d | |||
| fe575a38aa | |||
| 4c9558c586 | |||
| 2deee2b1b7 | |||
| 8e709eec2e | |||
| c7c7731f91 | |||
| 77f910ee36 | |||
| d000d2047d | |||
| 9d41e86866 | |||
| c15c97f69c | |||
| 5ed8be2466 | |||
| 6826c1eb69 | |||
| e772107c58 | |||
| c44c222557 | |||
| 8efefeeb5b | |||
| 59af763dcd | |||
| 2880d61c1b | |||
| f194f78953 | |||
| a5354f64a5 | |||
| 6d41aadc24 | |||
| 9a993c00e4 | |||
| 114c398056 | |||
| 384f1bd174 | |||
| 653a68b8a5 | |||
| 4a9f7b740c | |||
| 86de251691 | |||
| 0b2bc726df | |||
| b42967848e | |||
| 04af255045 | |||
| 3d759d76cf | |||
| 7c583fb1e6 | |||
| 9aaf95ca98 | |||
| 6dfd9bca69 | |||
| eadf472dd0 | |||
| 04ea1fb9ca | |||
| 947010ad01 | |||
| 3a05abe556 | |||
| a1c69082e2 | |||
| 467b082e82 | |||
| 5ab813179d | |||
| 8976746867 | |||
| fabbda659b | |||
| e9e1890b14 | |||
| 5c73a60551 | |||
| ae6a6a1d9c | |||
| 19c6760ea7 |
@@ -21,7 +21,7 @@ CWD=$(pwd)
|
||||
TMP=/tmp
|
||||
PKG=/$TMP/package-base-i2p
|
||||
NAME=i2p-base
|
||||
VERSION=0.0.3
|
||||
VERSION=0.0.4
|
||||
BUILD=1sponge
|
||||
ARCH=noarch
|
||||
INSTALL_DIR=opt
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
i2p_start() {
|
||||
# Check if router is up first!
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory status )" > /dev/null
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory status )'" > /dev/null
|
||||
if [ $? -eq 0 ] ; then {
|
||||
# I2p is already running, so tell the user.
|
||||
echo "I2P is already running..."
|
||||
@@ -14,13 +14,13 @@ i2p_start() {
|
||||
# Just in-case there are leftover junk in /tmp...
|
||||
rm -Rf `grep /tmp/hsperfdata_root/* -le i2p` /tmp/i2p-*.tmp /tmp/router.ping
|
||||
# Now that all junk is cleaned up, start.
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory start )"
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory start )'"
|
||||
}
|
||||
fi
|
||||
}
|
||||
|
||||
i2p_stop() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory stop )"
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory stop )'"
|
||||
rm -Rf `grep /tmp/hsperfdata_root/* -le i2p` /tmp/i2p-*.tmp /tmp/router.ping
|
||||
}
|
||||
|
||||
@@ -31,15 +31,15 @@ i2p_restart() {
|
||||
}
|
||||
|
||||
i2p_status() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory status )"
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory status )'"
|
||||
}
|
||||
|
||||
i2p_console() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory console )"
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory console )'"
|
||||
}
|
||||
|
||||
i2p_dump() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory dump )"
|
||||
/bin/su - -c "/bin/bash -l -c '( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\" ; directory dump )'"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
|
||||
@@ -137,7 +137,7 @@ public class ConnectionAcceptor implements Runnable
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Thread t = new I2PAppThread(new Handler(socket), "Connection-" + socket);
|
||||
Thread t = new I2PAppThread(new Handler(socket), "I2PSnark incoming connection");
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,13 @@ import java.util.StringTokenizer;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketEepGet;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
@@ -316,21 +318,44 @@ public class I2PSnarkUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static final int BASE32_HASH_LENGTH = 52; // 1 + Hash.HASH_LENGTH * 8 / 5
|
||||
|
||||
/** Base64 Hash or Hash.i2p or name.i2p using naming service */
|
||||
Destination getDestination(String ip) {
|
||||
if (ip == null) return null;
|
||||
if (ip.endsWith(".i2p")) {
|
||||
if (ip.length() < 520) { // key + ".i2p"
|
||||
Destination dest = _context.namingService().lookup(ip);
|
||||
if (dest != null)
|
||||
return dest;
|
||||
if (_manager != null && ip.length() == BASE32_HASH_LENGTH + 8 && ip.endsWith(".b32.i2p")) {
|
||||
// Use existing I2PSession for b32 lookups if we have it
|
||||
// This is much more efficient than using the naming service
|
||||
I2PSession sess = _manager.getSession();
|
||||
if (sess != null) {
|
||||
byte[] b = Base32.decode(ip.substring(0, BASE32_HASH_LENGTH));
|
||||
if (b != null) {
|
||||
Hash h = new Hash(b);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Using existing session for lookup of " + ip);
|
||||
try {
|
||||
return sess.lookupDest(h);
|
||||
} catch (I2PSessionException ise) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Using naming service for lookup of " + ip);
|
||||
return _context.namingService().lookup(ip);
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Creating Destination for " + ip);
|
||||
try {
|
||||
return new Destination(ip.substring(0, ip.length()-4)); // sans .i2p
|
||||
} catch (DataFormatException dfe) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Creating Destination for " + ip);
|
||||
try {
|
||||
return new Destination(ip);
|
||||
} catch (DataFormatException dfe) {
|
||||
|
||||
@@ -39,7 +39,13 @@ class Message
|
||||
final static byte REQUEST = 6;
|
||||
final static byte PIECE = 7;
|
||||
final static byte CANCEL = 8;
|
||||
final static byte EXTENSION = 20;
|
||||
final static byte PORT = 9; // DHT (BEP 5)
|
||||
final static byte SUGGEST = 13; // Fast (BEP 6)
|
||||
final static byte HAVE_ALL = 14; // Fast (BEP 6)
|
||||
final static byte HAVE_NONE = 15; // Fast (BEP 6)
|
||||
final static byte REJECT = 16; // Fast (BEP 6)
|
||||
final static byte ALLOWED_FAST = 17; // Fast (BEP 6)
|
||||
final static byte EXTENSION = 20; // BEP 10
|
||||
|
||||
// Not all fields are used for every message.
|
||||
// KEEP_ALIVE doesn't have a real wire representation
|
||||
|
||||
@@ -291,7 +291,7 @@ public class MetaInfo
|
||||
if (piece >= 0 && piece < pieces -1)
|
||||
return piece_length;
|
||||
else if (piece == pieces -1)
|
||||
return (int)(length - piece * piece_length);
|
||||
return (int)(length - ((long)piece * piece_length));
|
||||
else
|
||||
throw new IndexOutOfBoundsException("no piece: " + piece);
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ public class Peer implements Comparable
|
||||
// bytes per bt spec: 0011223344556677
|
||||
static final long OPTION_EXTENSION = 0x0000000000100000l;
|
||||
static final long OPTION_FAST = 0x0000000000000004l;
|
||||
static final long OPTION_DHT = 0x0000000000000001l;
|
||||
private long options;
|
||||
|
||||
/**
|
||||
@@ -77,7 +78,7 @@ public class Peer implements Comparable
|
||||
this.my_id = my_id;
|
||||
this.metainfo = metainfo;
|
||||
_id = ++__id;
|
||||
//_log.debug("Creating a new peer with " + peerID.getAddress().calculateHash().toBase64(), new Exception("creating"));
|
||||
//_log.debug("Creating a new peer with " + peerID.toString(), new Exception("creating"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +102,7 @@ public class Peer implements Comparable
|
||||
this.peerID = new PeerID(id, sock.getPeerDestination());
|
||||
_id = ++__id;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Creating a new peer with " + peerID.getAddress().calculateHash().toBase64(), new Exception("creating " + _id));
|
||||
_log.debug("Creating a new peer with " + peerID.toString(), new Exception("creating " + _id));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +198,7 @@ public class Peer implements Comparable
|
||||
throw new IllegalStateException("Peer already started");
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Running connection to " + peerID.getAddress().calculateHash().toBase64(), new Exception("connecting"));
|
||||
_log.debug("Running connection to " + peerID.toString(), new Exception("connecting"));
|
||||
try
|
||||
{
|
||||
// Do we need to handshake?
|
||||
@@ -430,6 +431,7 @@ public class Peer implements Comparable
|
||||
|
||||
/**
|
||||
* Are we currently requesting the piece?
|
||||
* @deprecated deadlocks
|
||||
* @since 0.8.1
|
||||
*/
|
||||
boolean isRequesting(int p) {
|
||||
|
||||
@@ -428,7 +428,7 @@ public class PeerCoordinator implements PeerListener
|
||||
peer.runConnection(_util, listener, bitfield);
|
||||
}
|
||||
};
|
||||
String threadName = peer.toString();
|
||||
String threadName = "Snark peer " + peer.toString();
|
||||
new I2PAppThread(r, threadName).start();
|
||||
return true;
|
||||
}
|
||||
@@ -591,10 +591,7 @@ public class PeerCoordinator implements PeerListener
|
||||
}
|
||||
if (piece == null)
|
||||
wantedSize = wantedPieces.size();
|
||||
} // synch
|
||||
|
||||
// Don't sync the following, deadlock from calling each Peer's isRequesting()
|
||||
|
||||
//Only request a piece we've requested before if there's no other choice.
|
||||
if (piece == null) {
|
||||
// AND if there are almost no wanted pieces left (real end game).
|
||||
@@ -612,22 +609,12 @@ public class PeerCoordinator implements PeerListener
|
||||
Piece p = it2.next();
|
||||
if (havePieces.get(p.getId())) {
|
||||
// limit number of parallel requests
|
||||
int requestedCount = 0;
|
||||
for (Peer pr : peers) {
|
||||
// deadlock if synced on wantedPieces
|
||||
if (pr.isRequesting(p.getId())) {
|
||||
if (pr.equals(peer)) {
|
||||
// don't give it to him again
|
||||
requestedCount = MAX_PARALLEL_REQUESTS;
|
||||
break;
|
||||
}
|
||||
if (++requestedCount >= MAX_PARALLEL_REQUESTS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (requestedCount >= MAX_PARALLEL_REQUESTS)
|
||||
continue;
|
||||
piece = p;
|
||||
int requestedCount = p.getRequestCount();
|
||||
if (requestedCount < MAX_PARALLEL_REQUESTS &&
|
||||
!p.isRequestedBy(peer)) {
|
||||
piece = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (piece == null) {
|
||||
@@ -648,9 +635,10 @@ public class PeerCoordinator implements PeerListener
|
||||
if (record) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(peer + " is now requesting: piece " + piece + " priority " + piece.getPriority());
|
||||
piece.setRequested(true);
|
||||
piece.setRequested(peer, true);
|
||||
}
|
||||
return piece.getId();
|
||||
} // synch
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -948,7 +936,7 @@ public class PeerCoordinator implements PeerListener
|
||||
}
|
||||
} // else drop the empty partial piece
|
||||
// synchs on wantedPieces...
|
||||
markUnrequestedIfOnlyOne(peer, pp.getPiece());
|
||||
markUnrequested(peer, pp.getPiece());
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Partial list size now: " + partialPieces.size());
|
||||
@@ -974,7 +962,7 @@ public class PeerCoordinator implements PeerListener
|
||||
// this is just a double-check, it should be in there
|
||||
for(Piece piece : wantedPieces) {
|
||||
if (piece.getId() == savedPiece) {
|
||||
piece.setRequested(true);
|
||||
piece.setRequested(peer, true);
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Restoring orphaned partial piece " + pp +
|
||||
" Partial list size now: " + partialPieces.size());
|
||||
@@ -1053,33 +1041,16 @@ public class PeerCoordinator implements PeerListener
|
||||
}
|
||||
}
|
||||
|
||||
/** Clear the requested flag for a piece if the peer
|
||||
** is the only one requesting it
|
||||
/**
|
||||
* Clear the requested flag for a piece
|
||||
*/
|
||||
private void markUnrequestedIfOnlyOne(Peer peer, int piece)
|
||||
private void markUnrequested(Peer peer, int piece)
|
||||
{
|
||||
// see if anybody else is requesting
|
||||
for (Peer p : peers) {
|
||||
if (p.equals(peer))
|
||||
continue;
|
||||
if (p.state == null)
|
||||
continue;
|
||||
// FIXME don't go into the state
|
||||
if (p.state.getRequestedPieces().contains(Integer.valueOf(piece))) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Another peer is requesting piece " + piece);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// nobody is, so mark unrequested
|
||||
synchronized(wantedPieces)
|
||||
{
|
||||
for (Piece pc : wantedPieces) {
|
||||
if (pc.getId() == piece) {
|
||||
pc.setRequested(false);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Removing from request list piece " + piece);
|
||||
pc.setRequested(peer, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,7 +464,7 @@ class PeerState implements DataLoader
|
||||
/**
|
||||
* @return all pieces we are currently requesting, or empty Set
|
||||
*/
|
||||
synchronized Set<Integer> getRequestedPieces() {
|
||||
synchronized private Set<Integer> getRequestedPieces() {
|
||||
Set<Integer> rv = new HashSet(outstandingRequests.size() + 1);
|
||||
for (Request req : outstandingRequests) {
|
||||
rv.add(Integer.valueOf(req.piece));
|
||||
@@ -564,6 +564,7 @@ class PeerState implements DataLoader
|
||||
|
||||
/**
|
||||
* Are we currently requesting the piece?
|
||||
* @deprecated deadlocks
|
||||
* @since 0.8.1
|
||||
*/
|
||||
synchronized boolean isRequesting(int piece) {
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
package org.klomp.snark;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
|
||||
/**
|
||||
* This class is used solely by PeerCoordinator.
|
||||
* Caller must synchronize on many of these methods.
|
||||
*/
|
||||
class Piece implements Comparable {
|
||||
|
||||
private int id;
|
||||
private Set<PeerID> peers;
|
||||
private boolean requested;
|
||||
private final int id;
|
||||
private final Set<PeerID> peers;
|
||||
/** @since 0.8.3 */
|
||||
private Set<PeerID> requests;
|
||||
/** @since 0.8.1 */
|
||||
private int priority;
|
||||
|
||||
public Piece(int id) {
|
||||
this.id = id;
|
||||
this.peers = new ConcurrentHashSet();
|
||||
this.peers = new HashSet(I2PSnarkUtil.MAX_CONNECTIONS);
|
||||
// defer creating requests to save memory
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,12 +50,51 @@ class Piece implements Comparable {
|
||||
}
|
||||
|
||||
public int getId() { return this.id; }
|
||||
/** @deprecated unused */
|
||||
public Set<PeerID> getPeers() { return this.peers; }
|
||||
|
||||
/** caller must synchronize */
|
||||
public boolean addPeer(Peer peer) { return this.peers.add(peer.getPeerID()); }
|
||||
|
||||
/** caller must synchronize */
|
||||
public boolean removePeer(Peer peer) { return this.peers.remove(peer.getPeerID()); }
|
||||
public boolean isRequested() { return this.requested; }
|
||||
public void setRequested(boolean requested) { this.requested = requested; }
|
||||
|
||||
/** caller must synchronize */
|
||||
public boolean isRequested() {
|
||||
return this.requests != null && !this.requests.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Since 0.8.3, keep track of who is requesting here,
|
||||
* to avoid deadlocks from querying each peer.
|
||||
* Caller must synchronize
|
||||
*/
|
||||
public void setRequested(Peer peer, boolean requested) {
|
||||
if (requested) {
|
||||
if (this.requests == null)
|
||||
this.requests = new HashSet(2);
|
||||
this.requests.add(peer.getPeerID());
|
||||
} else {
|
||||
if (this.requests != null)
|
||||
this.requests.remove(peer.getPeerID());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is peer requesting this piece?
|
||||
* Caller must synchronize
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public boolean isRequestedBy(Peer peer) {
|
||||
return this.requests != null && this.requests.contains(peer.getPeerID());
|
||||
}
|
||||
|
||||
/**
|
||||
* How many peers are requesting this piece?
|
||||
* Caller must synchronize
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public int getRequestCount() {
|
||||
return this.requests == null ? 0 : this.requests.size();
|
||||
}
|
||||
|
||||
/** @return default 0 @since 0.8.1 */
|
||||
public int getPriority() { return this.priority; }
|
||||
|
||||
@@ -72,8 +72,10 @@ public class TrackerClient extends I2PAppThread
|
||||
|
||||
public TrackerClient(I2PSnarkUtil util, MetaInfo meta, PeerCoordinator coordinator)
|
||||
{
|
||||
super();
|
||||
// Set unique name.
|
||||
super("TrackerClient-" + urlencode(coordinator.getID()));
|
||||
String id = urlencode(coordinator.getID());
|
||||
setName("TrackerClient " + id.substring(id.length() - 12));
|
||||
_util = util;
|
||||
this.meta = meta;
|
||||
this.coordinator = coordinator;
|
||||
@@ -274,7 +276,7 @@ public class TrackerClient extends I2PAppThread
|
||||
// only delay if we actually make an attempt to add peer
|
||||
if(coordinator.addPeer(cur)) {
|
||||
int delay = DELAY_MUL;
|
||||
delay *= ((int)cur.getPeerID().getAddress().calculateHash().toBase64().charAt(0)) % 10;
|
||||
delay *= r.nextInt(10);
|
||||
delay += DELAY_MIN;
|
||||
sleptTime += delay;
|
||||
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
||||
|
||||
@@ -157,7 +157,7 @@ public class BEValue
|
||||
* values. This operation only succeeds when the BEValue is actually
|
||||
* a Map, otherwise it will throw a InvalidBEncodingException.
|
||||
*/
|
||||
public Map<BEValue, BEValue> getMap() throws InvalidBEncodingException
|
||||
public Map<String, BEValue> getMap() throws InvalidBEncodingException
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -99,6 +99,17 @@ public class I2PSnarkServlet extends Default {
|
||||
return _resourceBase.addPath(pathInContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the browser to cache the icons
|
||||
* @since 0.8.3
|
||||
*/
|
||||
@Override
|
||||
public void handleGet(HttpServletRequest request, HttpServletResponse response, String pathInContext, Resource resource, boolean endsWithSlash) throws ServletException, IOException {
|
||||
if (resource.getName().startsWith("jar:file:"))
|
||||
response.setHeader("Cache-Control", "max-age=86400"); // cache for a day
|
||||
super.handleGet(request, response, pathInContext, resource, endsWithSlash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some parts modified from:
|
||||
* <pre>
|
||||
@@ -329,14 +340,18 @@ public class I2PSnarkServlet extends Default {
|
||||
|
||||
// Opera and text-mode browsers: no   and no input type=image values submitted
|
||||
String ua = req.getHeader("User-Agent");
|
||||
boolean isDegraded = ua != null && (ua.startsWith("Opera") || ua.startsWith("Lynx") ||
|
||||
boolean isDegraded = ua != null && (ua.startsWith("Lynx") ||
|
||||
ua.startsWith("ELinks") || ua.startsWith("Dillo"));
|
||||
|
||||
boolean noThinsp = isDegraded || ua.startsWith("Opera");
|
||||
if (_manager.util().connected()) {
|
||||
if (isDegraded)
|
||||
out.write("<a href=\"/i2psnark/?action=StopAll&nonce=" + _nonce + "\"><img title=\"");
|
||||
else
|
||||
out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\"");
|
||||
else {
|
||||
// http://www.onenaught.com/posts/382/firefox-4-change-input-type-image-only-submits-x-and-y-not-name
|
||||
//out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\"");
|
||||
out.write("<input type=\"image\" name=\"action_StopAll\" value=\"foo\" title=\"");
|
||||
}
|
||||
out.write(_("Stop all torrents and the I2P tunnel"));
|
||||
out.write("\" src=\"" + _imgPath + "stop_all.png\" alt=\"");
|
||||
out.write(_("Stop All"));
|
||||
@@ -347,7 +362,7 @@ public class I2PSnarkServlet extends Default {
|
||||
if (isDegraded)
|
||||
out.write("<a href=\"/i2psnark/?action=StartAll&nonce=" + _nonce + "\"><img title=\"");
|
||||
else
|
||||
out.write("<input type=\"image\" name=\"action\" value=\"StartAll\" title=\"");
|
||||
out.write("<input type=\"image\" name=\"action_StartAll\" value=\"foo\" title=\"");
|
||||
out.write(_("Start all torrents and the I2P tunnel"));
|
||||
out.write("\" src=\"" + _imgPath + "start_all.png\" alt=\"");
|
||||
out.write(_("Start All"));
|
||||
@@ -362,7 +377,7 @@ public class I2PSnarkServlet extends Default {
|
||||
Snark snark = (Snark)snarks.get(i);
|
||||
boolean showDebug = "2".equals(peerParam);
|
||||
boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam);
|
||||
displaySnark(out, snark, uri, i, stats, showPeers, isDegraded, showDebug);
|
||||
displaySnark(out, snark, uri, i, stats, showPeers, isDegraded, noThinsp, showDebug);
|
||||
}
|
||||
|
||||
if (snarks.isEmpty()) {
|
||||
@@ -404,8 +419,19 @@ public class I2PSnarkServlet extends Default {
|
||||
private void processRequest(HttpServletRequest req) {
|
||||
String action = req.getParameter("action");
|
||||
if (action == null) {
|
||||
_manager.addMessage("No action specified");
|
||||
return;
|
||||
// http://www.onenaught.com/posts/382/firefox-4-change-input-type-image-only-submits-x-and-y-not-name
|
||||
Map params = req.getParameterMap();
|
||||
for (Object o : params.keySet()) {
|
||||
String key = (String) o;
|
||||
if (key.startsWith("action_") && key.endsWith(".x")) {
|
||||
action = key.substring(0, key.length() - 2).substring(7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (action == null) {
|
||||
_manager.addMessage("No action specified");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// sadly, Opera doesn't send value with input type=image, so we have to use GET there
|
||||
//if (!"POST".equals(req.getMethod())) {
|
||||
@@ -698,7 +724,7 @@ public class I2PSnarkServlet extends Default {
|
||||
private static final int MAX_DISPLAYED_FILENAME_LENGTH = 50;
|
||||
private static final int MAX_DISPLAYED_ERROR_LENGTH = 43;
|
||||
private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers,
|
||||
boolean isDegraded, boolean showDebug) throws IOException {
|
||||
boolean isDegraded, boolean noThinsp, boolean showDebug) throws IOException {
|
||||
String filename = snark.torrent;
|
||||
File f = new File(filename);
|
||||
filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name
|
||||
@@ -758,11 +784,11 @@ public class I2PSnarkServlet extends Default {
|
||||
if (isRunning && curPeers > 0 && !showPeers)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
|
||||
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
|
||||
curPeers + thinsp(isDegraded) +
|
||||
curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
|
||||
else if (isRunning)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
|
||||
": " + curPeers + thinsp(isDegraded) +
|
||||
": " + curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers);
|
||||
else {
|
||||
if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
|
||||
@@ -774,11 +800,11 @@ public class I2PSnarkServlet extends Default {
|
||||
if (isRunning && curPeers > 0 && !showPeers)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") +
|
||||
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
|
||||
curPeers + thinsp(isDegraded) +
|
||||
curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
|
||||
else if (isRunning)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") +
|
||||
": " + curPeers + thinsp(isDegraded) +
|
||||
": " + curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers);
|
||||
else
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "complete.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Complete");
|
||||
@@ -786,24 +812,24 @@ public class I2PSnarkServlet extends Default {
|
||||
if (isRunning && curPeers > 0 && downBps > 0 && !showPeers)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
|
||||
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
|
||||
curPeers + thinsp(isDegraded) +
|
||||
curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
|
||||
else if (isRunning && curPeers > 0 && downBps > 0)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
|
||||
": " + curPeers + thinsp(isDegraded) +
|
||||
": " + curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers);
|
||||
else if (isRunning && curPeers > 0 && !showPeers)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
|
||||
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
|
||||
curPeers + thinsp(isDegraded) +
|
||||
curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
|
||||
else if (isRunning && curPeers > 0)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
|
||||
": " + curPeers + thinsp(isDegraded) +
|
||||
": " + curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers);
|
||||
else if (isRunning && knownPeers > 0)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers") +
|
||||
": 0" + thinsp(isDegraded) + knownPeers ;
|
||||
": 0" + thinsp(noThinsp) + knownPeers ;
|
||||
else if (isRunning)
|
||||
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers");
|
||||
else
|
||||
@@ -880,7 +906,7 @@ public class I2PSnarkServlet extends Default {
|
||||
out.write("</td>\n\t");
|
||||
out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
|
||||
if (remaining > 0)
|
||||
out.write(formatSize(total-remaining) + thinsp(isDegraded) + formatSize(total));
|
||||
out.write(formatSize(total-remaining) + thinsp(noThinsp) + formatSize(total));
|
||||
else
|
||||
out.write(formatSize(total)); // 3GB
|
||||
out.write("</td>\n\t");
|
||||
@@ -905,7 +931,7 @@ public class I2PSnarkServlet extends Default {
|
||||
if (isDegraded)
|
||||
out.write("<a href=\"/i2psnark/?action=Stop_" + b64 + "&nonce=" + _nonce + "\"><img title=\"");
|
||||
else
|
||||
out.write("<input type=\"image\" name=\"action\" value=\"Stop_" + b64 + "\" title=\"");
|
||||
out.write("<input type=\"image\" name=\"action_Stop_" + b64 + "\" value=\"foo\" title=\"");
|
||||
out.write(_("Stop the torrent"));
|
||||
out.write("\" src=\"" + _imgPath + "stop.png\" alt=\"");
|
||||
out.write(_("Stop"));
|
||||
@@ -917,7 +943,7 @@ public class I2PSnarkServlet extends Default {
|
||||
if (isDegraded)
|
||||
out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&nonce=" + _nonce + "\"><img title=\"");
|
||||
else
|
||||
out.write("<input type=\"image\" name=\"action\" value=\"Start_" + b64 + "\" title=\"");
|
||||
out.write("<input type=\"image\" name=\"action_Start_" + b64 + "\" value=\"foo\" title=\"");
|
||||
out.write(_("Start the torrent"));
|
||||
out.write("\" src=\"" + _imgPath + "start.png\" alt=\"");
|
||||
out.write(_("Start"));
|
||||
@@ -929,7 +955,7 @@ public class I2PSnarkServlet extends Default {
|
||||
if (isDegraded)
|
||||
out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&nonce=" + _nonce + "\"><img title=\"");
|
||||
else
|
||||
out.write("<input type=\"image\" name=\"action\" value=\"Remove_" + b64 + "\" title=\"");
|
||||
out.write("<input type=\"image\" name=\"action_Remove_" + b64 + "\" value=\"foo\" title=\"");
|
||||
out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
|
||||
out.write("\" onclick=\"if (!confirm('");
|
||||
// Can't figure out how to escape double quotes inside the onclick string.
|
||||
@@ -946,7 +972,7 @@ public class I2PSnarkServlet extends Default {
|
||||
if (isDegraded)
|
||||
out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&nonce=" + _nonce + "\"><img title=\"");
|
||||
else
|
||||
out.write("<input type=\"image\" name=\"action\" value=\"Delete_" + b64 + "\" title=\"");
|
||||
out.write("<input type=\"image\" name=\"action_Delete_" + b64 + "\" value=\"foo\" title=\"");
|
||||
out.write(_("Delete the .torrent file and the associated data file(s)"));
|
||||
out.write("\" onclick=\"if (!confirm('");
|
||||
// Can't figure out how to escape double quotes inside the onclick string.
|
||||
@@ -1384,7 +1410,7 @@ public class I2PSnarkServlet extends Default {
|
||||
private static String urlify(String s) {
|
||||
StringBuilder buf = new StringBuilder(256);
|
||||
// browsers seem to work without doing this but let's be strict
|
||||
String link = s.replace("&", "&");
|
||||
String link = s.replace("&", "&").replace(" ", "%20");
|
||||
buf.append("<a href=\"").append(link).append("\">").append(link).append("</a>");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Project-Id-Version: I2P i2psnark\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-12-19 03:16+0000\n"
|
||||
"PO-Revision-Date: 2010-12-19 04:49+0100\n"
|
||||
"PO-Revision-Date: 2011-01-03 00:58+0100\n"
|
||||
"Last-Translator: mixxy <m1xxy@mail.i2p>\n"
|
||||
"Language-Team: foo <foo@bar>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -269,7 +269,7 @@ msgstr "Tiempo restante para completar la descarga"
|
||||
#. Translators: Please keep short or translate as " "
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:293
|
||||
msgid "ETA"
|
||||
msgstr "Completado en"
|
||||
msgstr "Tiempo"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:297
|
||||
msgid "Downloaded"
|
||||
@@ -323,7 +323,7 @@ msgstr "Arrancar todos"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:372
|
||||
msgid "No torrents loaded."
|
||||
msgstr "No cargado ningún torrent"
|
||||
msgstr "No está cargado ningún torrent"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:377
|
||||
msgid "Totals"
|
||||
@@ -453,7 +453,7 @@ msgstr "completo"
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:787
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:792
|
||||
msgid "OK"
|
||||
msgstr "Bien"
|
||||
msgstr "bien"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:796
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:801
|
||||
@@ -644,7 +644,7 @@ msgstr "Si marcado, los torrents añadidos se iniciarán de forma automática."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1198
|
||||
msgid "Theme"
|
||||
msgstr "tema"
|
||||
msgstr "Tema"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1211
|
||||
msgid "Startup delay"
|
||||
@@ -664,7 +664,7 @@ msgstr "pares"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1244
|
||||
msgid "Up bandwidth limit"
|
||||
msgstr "Límite de ancho de banda para la subida"
|
||||
msgstr "Límite del ancho de banda para la subida"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1247
|
||||
msgid "Half available bandwidth recommended."
|
||||
@@ -696,7 +696,7 @@ msgstr "Preferencias de salida"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1286
|
||||
msgid "I2CP host"
|
||||
msgstr "Huésped I2CP"
|
||||
msgstr "Anfitrión I2CP"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1291
|
||||
msgid "I2CP port"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P i2psnark\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-12-17 15:04+0000\n"
|
||||
"POT-Creation-Date: 2011-01-20 19:26+0000\n"
|
||||
"PO-Revision-Date: 2010-06-15 09:07+0100\n"
|
||||
"Last-Translator: duck <duck@mail.i2p>\n"
|
||||
"Language-Team: duck <duck@mail.i2p>, monkeybrains <monkeybrains@mail.i2p>\n"
|
||||
@@ -104,7 +104,8 @@ msgstr "Open Tracker lijst gewijzigd - torrent herstart nodig."
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:438
|
||||
#, java-format
|
||||
msgid "{0} theme loaded, return to main i2psnark page to view."
|
||||
msgstr "{0} thema geladen, ga naar de hoofd i2psnark pagina om deze te bekijken."
|
||||
msgstr ""
|
||||
"{0} thema geladen, ga naar de hoofd i2psnark pagina om deze te bekijken."
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:445
|
||||
msgid "Configuration unchanged."
|
||||
@@ -234,176 +235,176 @@ msgstr "Kan niet verbinden met I2P!"
|
||||
msgid "Unable to add {0}"
|
||||
msgstr "Kan {0} niet toevoegen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:185
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:196
|
||||
msgid "I2PSnark - Anonymous BitTorrent Client"
|
||||
msgstr "I2PSnark - Anonieme BitTorrent Client"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:198
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:209
|
||||
msgid "Torrents"
|
||||
msgstr "Torrents"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:201
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:208
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:977
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:212
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:219
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1003
|
||||
msgid "I2PSnark"
|
||||
msgstr "I2PSnark"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:205
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:216
|
||||
msgid "Refresh page"
|
||||
msgstr "Ververs pagina"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:210
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:221
|
||||
msgid "Forum"
|
||||
msgstr "Forum"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:264
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1483
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:275
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1509
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:270
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:272
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:281
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:283
|
||||
msgid "Hide Peers"
|
||||
msgstr "Verberg Peers"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:277
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:279
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:288
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:290
|
||||
msgid "Show Peers"
|
||||
msgstr "Toon Peers"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:286
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1464
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:297
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1490
|
||||
msgid "Torrent"
|
||||
msgstr "Torrent"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:290
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:301
|
||||
msgid "Estimated time remaining"
|
||||
msgstr "Schatting resterende tijd"
|
||||
|
||||
#. Translators: Please keep short or translate as " "
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:293
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:304
|
||||
msgid "ETA"
|
||||
msgstr "ETA"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:297
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:308
|
||||
msgid "Downloaded"
|
||||
msgstr "Gedownload"
|
||||
|
||||
#. Translators: Please keep short or translate as " "
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:300
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:314
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:311
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:325
|
||||
msgid "RX"
|
||||
msgstr "RX"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:304
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:315
|
||||
msgid "Uploaded"
|
||||
msgstr "Geupload"
|
||||
|
||||
#. Translators: Please keep short or translate as " "
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:307
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:324
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:318
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:335
|
||||
msgid "TX"
|
||||
msgstr "TX"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:312
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:323
|
||||
msgid "Down Rate"
|
||||
msgstr "Down Snelheid"
|
||||
|
||||
#. Translators: Please keep short or translate as " "
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:317
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:326
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:328
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:337
|
||||
msgid "Rate"
|
||||
msgstr "Rato"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:322
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:333
|
||||
msgid "Up Rate"
|
||||
msgstr "Up Snelheid"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:340
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:355
|
||||
msgid "Stop all torrents and the I2P tunnel"
|
||||
msgstr "Stop alle torrents en de I2P tunnel"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:342
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:357
|
||||
msgid "Stop All"
|
||||
msgstr "Stop Alle"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:351
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:366
|
||||
msgid "Start all torrents and the I2P tunnel"
|
||||
msgstr "Start alle torrents en de I2P tunnel"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:353
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:368
|
||||
msgid "Start All"
|
||||
msgstr "Start Alle"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:372
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:387
|
||||
msgid "No torrents loaded."
|
||||
msgstr "Geen torrents geladen."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:377
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:392
|
||||
msgid "Totals"
|
||||
msgstr "Totalen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:379
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:394
|
||||
#, java-format
|
||||
msgid "1 torrent"
|
||||
msgid_plural "{0} torrents"
|
||||
msgstr[0] "1 torrent"
|
||||
msgstr[1] "{0} torrents"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:382
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:397
|
||||
#, java-format
|
||||
msgid "1 connected peer"
|
||||
msgid_plural "{0} connected peers"
|
||||
msgstr[0] "1 verbonden peer"
|
||||
msgstr[1] "{0} verbonden peers"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:454
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:480
|
||||
#, java-format
|
||||
msgid "Fetching {0}"
|
||||
msgstr "Downloaden {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:458
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:484
|
||||
msgid "Invalid URL - must start with http://"
|
||||
msgstr "Ongeldige URL - moet beginnen met http://"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:489
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:515
|
||||
#, java-format
|
||||
msgid "Starting up torrent {0}"
|
||||
msgstr "Starten met torrent {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:509
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:527
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:553
|
||||
#, java-format
|
||||
msgid "Torrent file deleted: {0}"
|
||||
msgstr "Torrent bestand verwijderd: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:533
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:543
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:559
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:569
|
||||
#, java-format
|
||||
msgid "Data file deleted: {0}"
|
||||
msgstr "Data bestand verwijderd: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:545
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:561
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:571
|
||||
#, java-format
|
||||
msgid "Data file could not be deleted: {0}"
|
||||
msgstr "Kan data bestand niet verwijderen: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:554
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:580
|
||||
#, java-format
|
||||
msgid "Data dir deleted: {0}"
|
||||
msgstr "Data directory verwijderd: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:587
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:613
|
||||
msgid "Error creating torrent - you must select a tracker"
|
||||
msgstr "Fout bij maken van torrent - je moet een tracker selecteren"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:602
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:628
|
||||
#, java-format
|
||||
msgid "Torrent created for \"{0}\""
|
||||
msgstr "Torrent gemaakt voor \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:605
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:631
|
||||
#, java-format
|
||||
msgid ""
|
||||
"Many I2P trackers require you to register new torrents before seeding - "
|
||||
@@ -412,121 +413,121 @@ msgstr ""
|
||||
"Veel I2P trackers vereisen dat je de nieuwe torrent registreert voor het "
|
||||
"seeden - doe dit voordat je \"{0}\" start"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:607
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:633
|
||||
#, java-format
|
||||
msgid "Error creating a torrent for \"{0}\""
|
||||
msgstr "Fout bij het maken van een torrent voor \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:610
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:636
|
||||
#, java-format
|
||||
msgid "Cannot create a torrent for the nonexistent data: {0}"
|
||||
msgstr "Kan geen torrent maken voor niet-bestaande data: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:613
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:639
|
||||
msgid "Error creating torrent - you must enter a file or directory"
|
||||
msgstr ""
|
||||
"Fout bij het maken van de torrent - je moet een bestand of directory invullen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:616
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:642
|
||||
msgid "Stopping all torrents and closing the I2P tunnel."
|
||||
msgstr "Stoppen van alle torrents en sluiten van I2P tunnel."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:627
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:653
|
||||
msgid "I2P tunnel closed."
|
||||
msgstr "I2P tunnel gesloten."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:630
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:656
|
||||
msgid "Opening the I2P tunnel and starting all torrents."
|
||||
msgstr "Openen van de I2P tunnel en starten van alle torrents."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:759
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:764
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:770
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:785
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:790
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:796
|
||||
msgid "Tracker Error"
|
||||
msgstr "Tracker Fout"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:762
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:766
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:778
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:782
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:790
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:794
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:799
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:803
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:788
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:792
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:804
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:808
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:816
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:820
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:825
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:829
|
||||
#, java-format
|
||||
msgid "1 peer"
|
||||
msgid_plural "{0} peers"
|
||||
msgstr[0] "1 peer"
|
||||
msgstr[1] "{0} peers"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:775
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:780
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:801
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:806
|
||||
msgid "Seeding"
|
||||
msgstr "Seeding"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:784
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1533
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:810
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1559
|
||||
msgid "Complete"
|
||||
msgstr "Voltooid"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:787
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:792
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:813
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:818
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:796
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:801
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:822
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:827
|
||||
msgid "Stalled"
|
||||
msgstr "Vastgelopen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:805
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:808
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:831
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:834
|
||||
msgid "No Peers"
|
||||
msgstr "Geen Peers"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:810
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:836
|
||||
msgid "Stopped"
|
||||
msgstr "Gestopt"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:837
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:863
|
||||
#, java-format
|
||||
msgid "Details at {0} tracker"
|
||||
msgstr "Details op de {0} tracker"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:838
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:864
|
||||
msgid "Info"
|
||||
msgstr "Info"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:853
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:879
|
||||
msgid "View files"
|
||||
msgstr "Bekijk bestanden"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:855
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:881
|
||||
msgid "Open file"
|
||||
msgstr "Open bestand"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:865
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1569
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:891
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1595
|
||||
msgid "Open"
|
||||
msgstr "Open"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:909
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:935
|
||||
msgid "Stop the torrent"
|
||||
msgstr "Stop de torrent"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:911
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:937
|
||||
msgid "Stop"
|
||||
msgstr "Stop"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:921
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:947
|
||||
msgid "Start the torrent"
|
||||
msgstr "Start de torrent"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:923
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:949
|
||||
msgid "Start"
|
||||
msgstr "Start"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:933
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:959
|
||||
msgid "Remove the torrent from the active list, deleting the .torrent file"
|
||||
msgstr ""
|
||||
"Verwijder de torrent van de actieve lijst, het .torrent bestand wordt "
|
||||
@@ -535,7 +536,7 @@ msgstr ""
|
||||
#. Can't figure out how to escape double quotes inside the onclick string.
|
||||
#. Single quotes in translate strings with parameters must be doubled.
|
||||
#. Then the remaining single quite must be escaped
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:938
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:964
|
||||
#, java-format
|
||||
msgid ""
|
||||
"Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded "
|
||||
@@ -544,18 +545,18 @@ msgstr ""
|
||||
"Weet je zeker dat je het bestand \\''{0}.torrent\\'' wilt verwijderen "
|
||||
"(gedownloade data zal niet worden verwijderd) ?"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:941
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:967
|
||||
msgid "Remove"
|
||||
msgstr "Weghalen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:950
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:976
|
||||
msgid "Delete the .torrent file and the associated data file(s)"
|
||||
msgstr "Verwijder het .torrent bestand en de gerelateerde data bestand(en)"
|
||||
|
||||
#. Can't figure out how to escape double quotes inside the onclick string.
|
||||
#. Single quotes in translate strings with parameters must be doubled.
|
||||
#. Then the remaining single quite must be escaped
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:955
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:981
|
||||
#, java-format
|
||||
msgid ""
|
||||
"Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded "
|
||||
@@ -564,151 +565,151 @@ msgstr ""
|
||||
"Weet je zeker dat je de torrent \\''{0}\\'' en alle gedownloade data wilt "
|
||||
"verwijderen?"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:958
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:984
|
||||
msgid "Delete"
|
||||
msgstr "Verwijderen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:991
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1017
|
||||
msgid "Unknown"
|
||||
msgstr "Onbekend"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1001
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1027
|
||||
msgid "Seed"
|
||||
msgstr "Seed"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1019
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1045
|
||||
msgid "Uninteresting (The peer has no pieces we need)"
|
||||
msgstr "Niet interessant (De peer heeft geen stukken die we nodig hebben)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1021
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1047
|
||||
msgid "Choked (The peer is not allowing us to request pieces)"
|
||||
msgstr "Verstikt (De peer laat ons niet toe om stukken op te vragen)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1035
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1061
|
||||
msgid "Uninterested (We have no pieces the peer needs)"
|
||||
msgstr "Niet geïnteresseerd (We heben geen stukken die de peer nodig heeft)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1037
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1063
|
||||
msgid "Choking (We are not allowing the peer to request pieces)"
|
||||
msgstr "Verstikt (We laten de peer niet toe om stukken op te vragen)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1092
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1118
|
||||
msgid "Add Torrent"
|
||||
msgstr "Torrent Toevoegen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1094
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1120
|
||||
msgid "From URL"
|
||||
msgstr "Van URL"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1097
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1123
|
||||
msgid "Torrent file must originate from an I2P-based tracker"
|
||||
msgstr "Torrent bestand moet vaan een I2P tracker komen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1102
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1128
|
||||
msgid "Add torrent"
|
||||
msgstr "Torrent toevoegen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1105
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1131
|
||||
#, java-format
|
||||
msgid "You can also copy .torrent files to: {0}."
|
||||
msgstr "Je kan ook .torrent bestanden kopieren naar: {0}."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1107
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1133
|
||||
msgid "Removing a .torrent will cause it to stop."
|
||||
msgstr "Verwijderen van een .torrent zorgt dat deze stopt."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1131
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1157
|
||||
msgid "Create Torrent"
|
||||
msgstr "Creëer Torrent"
|
||||
|
||||
#. out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br>\n");
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1134
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1160
|
||||
msgid "Data to seed"
|
||||
msgstr "Data om te seeden"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1138
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1164
|
||||
msgid "File or directory to seed (must be within the specified path)"
|
||||
msgstr ""
|
||||
"Bestand of directory om te seeden (moet binnen het gespecificeerde pad zijn)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1140
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1166
|
||||
msgid "Tracker"
|
||||
msgstr "Tracker"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1142
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1168
|
||||
msgid "Select a tracker"
|
||||
msgstr "Selecteer een tracker"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1155
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1181
|
||||
msgid "or"
|
||||
msgstr "of"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1158
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1184
|
||||
msgid "Specify custom tracker announce URL"
|
||||
msgstr "Specificeer aangepaste tracker aankondigings URL"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1161
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1187
|
||||
msgid "Create torrent"
|
||||
msgstr "Creëer torrent"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1180
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1317
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1206
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1343
|
||||
msgid "Configuration"
|
||||
msgstr "Configuratie"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1184
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1210
|
||||
msgid "Data directory"
|
||||
msgstr "Data directory"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1186
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1212
|
||||
msgid "Edit i2psnark.config and restart to change"
|
||||
msgstr "Bewerk i2psnark.config en herstart de wijziging"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1190
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1216
|
||||
msgid "Auto start"
|
||||
msgstr "Auto start"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1194
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1220
|
||||
msgid "If checked, automatically start torrents that are added"
|
||||
msgstr "Indien aangevinkt, start toegevoegde torrents automatisch"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1198
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1224
|
||||
msgid "Theme"
|
||||
msgstr "Thema"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1211
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1237
|
||||
msgid "Startup delay"
|
||||
msgstr "Startup vertraging"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1213
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1239
|
||||
msgid "minutes"
|
||||
msgstr "minuten"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1237
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1263
|
||||
msgid "Total uploader limit"
|
||||
msgstr "Totale uploader limiet"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1240
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1266
|
||||
msgid "peers"
|
||||
msgstr "peers"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1244
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1270
|
||||
msgid "Up bandwidth limit"
|
||||
msgstr "Up bandbreedte limiet"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1247
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1273
|
||||
msgid "Half available bandwidth recommended."
|
||||
msgstr "Helft van beschikbare bandbreedte aanbevolen."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1249
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1275
|
||||
msgid "View or change router bandwidth"
|
||||
msgstr "Bekijk of wijzig router bandbreedte"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1253
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1279
|
||||
msgid "Use open trackers also"
|
||||
msgstr "Gebruik ook open trackers"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1257
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1283
|
||||
msgid ""
|
||||
"If checked, announce torrents to open trackers as well as the tracker listed "
|
||||
"in the torrent file"
|
||||
@@ -716,123 +717,123 @@ msgstr ""
|
||||
"Indien aangevinkt, kondig torrents ook aan bij de tracker uit het torrent "
|
||||
"bestand"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1261
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1287
|
||||
msgid "Open tracker announce URLs"
|
||||
msgstr "Open tracker aankondigings URLs"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1273
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1299
|
||||
msgid "Inbound Settings"
|
||||
msgstr "Inkomende Instellingen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1279
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1305
|
||||
msgid "Outbound Settings"
|
||||
msgstr "Uitgaande Instellingen"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1286
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1312
|
||||
msgid "I2CP host"
|
||||
msgstr "I2CP host"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1291
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1317
|
||||
msgid "I2CP port"
|
||||
msgstr "I2CP poort"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1303
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1329
|
||||
msgid "I2CP options"
|
||||
msgstr "I2CP opties"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1308
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1334
|
||||
msgid "Save configuration"
|
||||
msgstr "Configuratie opslaan"
|
||||
|
||||
#. * dummies for translation
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1325
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1351
|
||||
#, java-format
|
||||
msgid "1 hop"
|
||||
msgid_plural "{0} hops"
|
||||
msgstr[0] "1 hop"
|
||||
msgstr[1] "{0} hops"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1326
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1352
|
||||
#, java-format
|
||||
msgid "1 tunnel"
|
||||
msgid_plural "{0} tunnels"
|
||||
msgstr[0] "1 tunnel"
|
||||
msgstr[1] "{0} tunnels"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1480
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1506
|
||||
msgid "Size"
|
||||
msgstr "Grootte"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1487
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1513
|
||||
msgid "Priority"
|
||||
msgstr "Prioriteit"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1492
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1518
|
||||
msgid "Up to higher level directory"
|
||||
msgstr "Naar bovenliggende directory"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1517
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1543
|
||||
msgid "Directory"
|
||||
msgstr "Directory"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1522
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1548
|
||||
msgid "Torrent not found?"
|
||||
msgstr "Torrent niet gevonden?"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1530
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1556
|
||||
msgid "File not found in torrent?"
|
||||
msgstr "Bestand niet gevonden in torrent?"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1543
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1569
|
||||
msgid "complete"
|
||||
msgstr "voltooid"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1544
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1570
|
||||
msgid "bytes remaining"
|
||||
msgstr "bytes resterend"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1595
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1621
|
||||
msgid "High"
|
||||
msgstr "Hoog"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1600
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1626
|
||||
msgid "Normal"
|
||||
msgstr "Normaal"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1605
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1631
|
||||
msgid "Skip"
|
||||
msgstr "Overslaan"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1614
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1640
|
||||
msgid "Save priorities"
|
||||
msgstr "Prioriteiten opslaan"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1726
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1752
|
||||
#, java-format
|
||||
msgid "Torrent fetched from {0}"
|
||||
msgstr "Torrent gedownload van {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1746
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1772
|
||||
#, java-format
|
||||
msgid "Torrent already running: {0}"
|
||||
msgstr "Torrent draait al: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1748
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1774
|
||||
#, java-format
|
||||
msgid "Torrent already in the queue: {0}"
|
||||
msgstr "Torrent zit al in de wachtrij: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1755
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1781
|
||||
#, java-format
|
||||
msgid "Failed to copy torrent file to {0}"
|
||||
msgstr "Kan het torrent bestand niet kopieren naar {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1759
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1785
|
||||
#, java-format
|
||||
msgid "Torrent at {0} was not valid"
|
||||
msgstr "Torrent op {0} was niet geldig"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1764
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1790
|
||||
#, java-format
|
||||
msgid "Torrent was not retrieved from {0}"
|
||||
msgstr "Torrent was niet ontvangen van {0}"
|
||||
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Project-Id-Version: I2P i2psnark\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-12-19 03:16+0000\n"
|
||||
"PO-Revision-Date: 2010-12-19 04:48+0100\n"
|
||||
"PO-Revision-Date: 2010-12-31 01:09+0100\n"
|
||||
"Last-Translator: mixxy <m1xxy@mail.i2p>\n"
|
||||
"Language-Team: foo <foo@bar>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -118,12 +118,12 @@ msgstr "Conectando com I2P"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:497
|
||||
msgid "Error connecting to I2P - check your I2CP settings!"
|
||||
msgstr "Error ao se conectar com I2P - Verifique a sua configuração I2CP!"
|
||||
msgstr "Erro ao se conectar com I2P - Verifique a sua configuração I2CP!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:506
|
||||
#, java-format
|
||||
msgid "Error: Could not add the torrent {0}"
|
||||
msgstr "Error: Não se pode adicionar o torrent {0}."
|
||||
msgstr "Erro: Não se pode adicionar o torrent {0}."
|
||||
|
||||
#. catch this here so we don't try do delete it below
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:528
|
||||
@@ -194,7 +194,7 @@ msgstr "Torrents maiores que \"{0}\" Bytes ainda não funcionam, se apagará \"{
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:767
|
||||
#, java-format
|
||||
msgid "Error: Could not remove the torrent {0}"
|
||||
msgstr "Error: Não se pode quitar o torrent \"{0}\"."
|
||||
msgstr "Erro: Não se pode quitar o torrent \"{0}\"."
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:794
|
||||
#, java-format
|
||||
@@ -269,7 +269,7 @@ msgstr "Tempo que falta para completar"
|
||||
#. Translators: Please keep short or translate as " "
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:293
|
||||
msgid "ETA"
|
||||
msgstr "Completado em"
|
||||
msgstr "Tempo"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:297
|
||||
msgid "Downloaded"
|
||||
@@ -299,7 +299,7 @@ msgstr "Taça de descarga"
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:317
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:326
|
||||
msgid "Rate"
|
||||
msgstr "Tasa"
|
||||
msgstr "Taça"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:322
|
||||
msgid "Up Rate"
|
||||
@@ -382,7 +382,7 @@ msgstr "Apagada a pasta de dados: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:587
|
||||
msgid "Error creating torrent - you must select a tracker"
|
||||
msgstr "Error ao criar o torrent - Tens que elegir um rastreador."
|
||||
msgstr "Erro ao criar o torrent - Tens que elegir um rastreador."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:602
|
||||
#, java-format
|
||||
@@ -392,12 +392,12 @@ msgstr "Torrent criado para \"{0}\""
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:605
|
||||
#, java-format
|
||||
msgid "Many I2P trackers require you to register new torrents before seeding - please do so before starting \"{0}\""
|
||||
msgstr "Muitos rastreadores no I2P exigem que você registre novos torrents antes de poder sembrá-los. Por favor, faça isto antes de iniciar \"{0}\"!"
|
||||
msgstr "Muitos rastreadores no I2P exigem que você registre novos torrents antes de poder semeá-los. Por favor, faça isto antes de iniciar \"{0}\"!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:607
|
||||
#, java-format
|
||||
msgid "Error creating a torrent for \"{0}\""
|
||||
msgstr "Error ao criar o torrent \"{0}\""
|
||||
msgstr "Erro ao criar o torrent \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:610
|
||||
#, java-format
|
||||
@@ -406,7 +406,7 @@ msgstr "Não se pode criar um torrent para dados que não existam: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:613
|
||||
msgid "Error creating torrent - you must enter a file or directory"
|
||||
msgstr "Error ao criar o torrent - Tens que especificar um arquivo ou uma pasta."
|
||||
msgstr "Erro ao criar o torrent - Tens que especificar um arquivo ou uma pasta."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:616
|
||||
msgid "Stopping all torrents and closing the I2P tunnel."
|
||||
@@ -424,7 +424,7 @@ msgstr "Abrendo o túnel I2P e iniciando os torrents ..."
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:764
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:770
|
||||
msgid "Tracker Error"
|
||||
msgstr "Error do rastreador"
|
||||
msgstr "Erro do rastreador"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:762
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:766
|
||||
@@ -443,7 +443,7 @@ msgstr[1] "{0} pares"
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:775
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:780
|
||||
msgid "Seeding"
|
||||
msgstr "sembrando"
|
||||
msgstr "semeando"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:784
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1533
|
||||
@@ -453,7 +453,7 @@ msgstr "completo"
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:787
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:792
|
||||
msgid "OK"
|
||||
msgstr "Bien"
|
||||
msgstr "bem"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:796
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:801
|
||||
@@ -545,7 +545,7 @@ msgstr "desconhecido"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1001
|
||||
msgid "Seed"
|
||||
msgstr "Sembrador"
|
||||
msgstr "Semeador"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1019
|
||||
msgid "Uninteresting (The peer has no pieces we need)"
|
||||
@@ -595,11 +595,11 @@ msgstr "Criar um torrent"
|
||||
#. out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br>\n");
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1134
|
||||
msgid "Data to seed"
|
||||
msgstr "Dados para sembrar"
|
||||
msgstr "Dados para semear"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1138
|
||||
msgid "File or directory to seed (must be within the specified path)"
|
||||
msgstr "Arquivo ou pasta para sembrar (deve estar no caminho especificado)"
|
||||
msgstr "Arquivo ou pasta para semear (deve estar no caminho especificado)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1140
|
||||
msgid "Tracker"
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.ByteArray;
|
||||
@@ -228,7 +229,15 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
//out.flush();
|
||||
PipedInputStream pi = new PipedInputStream();
|
||||
PipedOutputStream po = new PipedOutputStream(pi);
|
||||
new I2PAppThread(new Pusher(pi, out), "HTTP decompressor").start();
|
||||
// Run in the client thread pool, as there should be an unused thread
|
||||
// there after the accept().
|
||||
// Overridden in I2PTunnelHTTPServer, where it does not use the client pool.
|
||||
try {
|
||||
I2PTunnelClientBase._executor.execute(new Pusher(pi, out));
|
||||
} catch (RejectedExecutionException ree) {
|
||||
// shouldn't happen
|
||||
throw ree;
|
||||
}
|
||||
out = po;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@ import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelClient extends I2PTunnelClientBase {
|
||||
|
||||
private static final Log _log = new Log(I2PTunnelClient.class);
|
||||
|
||||
/** list of Destination objects that we point at */
|
||||
protected List<Destination> dests;
|
||||
private static final long DEFAULT_READ_TIMEOUT = 5*60*1000; // -1
|
||||
|
||||
@@ -17,6 +17,13 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
@@ -34,9 +41,9 @@ import net.i2p.util.SimpleTimer;
|
||||
|
||||
public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runnable {
|
||||
|
||||
private static final Log _log = new Log(I2PTunnelClientBase.class);
|
||||
protected I2PAppContext _context;
|
||||
protected Logging l;
|
||||
protected final Log _log;
|
||||
protected final I2PAppContext _context;
|
||||
protected final Logging l;
|
||||
|
||||
static final long DEFAULT_CONNECT_TIMEOUT = 60 * 1000;
|
||||
|
||||
@@ -64,35 +71,24 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
private String handlerName;
|
||||
private String privKeyFile;
|
||||
|
||||
// private Object conLock = new Object();
|
||||
|
||||
/** List of Socket for those accept()ed but not yet started up */
|
||||
protected final List _waitingSockets = new ArrayList(4); // FIXME should be final and use a factory. FIXME
|
||||
/** How many connections will we allow to be in the process of being built at once? */
|
||||
private int _numConnectionBuilders;
|
||||
/** How long will we allow sockets to sit in the _waitingSockets map before killing them? */
|
||||
private int _maxWaitTime;
|
||||
|
||||
/**
|
||||
* How many concurrent connections this I2PTunnel instance will allow to be
|
||||
* in the process of connecting (or if less than 1, there is no limit)?
|
||||
*/
|
||||
public static final String PROP_NUM_CONNECTION_BUILDERS = "i2ptunnel.numConnectionBuilders";
|
||||
/**
|
||||
* How long will we let a socket wait after being accept()ed without getting
|
||||
* pumped through a connection builder (in milliseconds). If this time is
|
||||
* reached, the socket is unceremoniously closed and discarded. If the max
|
||||
* wait time is less than 1, there is no limit.
|
||||
*
|
||||
*/
|
||||
public static final String PROP_MAX_WAIT_TIME = "i2ptunnel.maxWaitTime";
|
||||
|
||||
private static final int DEFAULT_NUM_CONNECTION_BUILDERS = 5;
|
||||
private static final int DEFAULT_MAX_WAIT_TIME = 30*1000;
|
||||
|
||||
// true if we are chained from a server.
|
||||
private boolean chained = false;
|
||||
|
||||
/** how long to wait before dropping an idle thread */
|
||||
private static final long HANDLER_KEEPALIVE_MS = 2*60*1000;
|
||||
|
||||
/**
|
||||
* We keep a static pool of socket handlers for all clients,
|
||||
* as there is no need for isolation on the client side.
|
||||
* Extending classes may use it for other purposes.
|
||||
* Not for use by servers, as there is no limit on threads.
|
||||
*/
|
||||
static final Executor _executor;
|
||||
private static int _executorThreadCount;
|
||||
static {
|
||||
_executor = new CustomThreadPoolExecutor();
|
||||
}
|
||||
|
||||
public I2PTunnelClientBase(int localPort, Logging l, I2PSocketManager sktMgr,
|
||||
I2PTunnel tunnel, EventDispatcher notifyThis, long clientId )
|
||||
throws IllegalArgumentException {
|
||||
@@ -102,16 +98,16 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
_clientId = clientId;
|
||||
this.localPort = localPort;
|
||||
this.l = l;
|
||||
this.handlerName = handlerName + _clientId;
|
||||
this.handlerName = localPort + " #" + _clientId;
|
||||
_ownDest = true; // == ! shared client
|
||||
_context = tunnel.getContext();
|
||||
_context.statManager().createRateStat("i2ptunnel.client.closeBacklog", "How many pending sockets remain when we close one due to backlog?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.closeNoBacklog", "How many pending sockets remain when it was removed prior to backlog timeout?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_log = _context.logManager().getLog(getClass());
|
||||
|
||||
Thread t = new I2PAppThread(this);
|
||||
t.setName("Client " + _clientId);
|
||||
Thread t = new I2PAppThread(this, "Client " + tunnel.listenHost + ':' + localPort);
|
||||
listenerReady = false;
|
||||
t.start();
|
||||
open = true;
|
||||
@@ -125,8 +121,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
configurePool(tunnel);
|
||||
|
||||
if (open && listenerReady) {
|
||||
l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
|
||||
notifyEvent("openBaseClientResult", "ok");
|
||||
@@ -135,6 +129,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
notifyEvent("openBaseClientResult", "error");
|
||||
}
|
||||
}
|
||||
|
||||
public I2PTunnelClientBase(int localPort, boolean ownDest, Logging l,
|
||||
EventDispatcher notifyThis, String handlerName,
|
||||
I2PTunnel tunnel) throws IllegalArgumentException {
|
||||
@@ -163,6 +158,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
_context.statManager().createRateStat("i2ptunnel.client.closeNoBacklog", "How many pending sockets remain when it was removed prior to backlog timeout?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_log = _context.logManager().getLog(getClass());
|
||||
|
||||
// normalize path so we can find it
|
||||
if (pkf != null) {
|
||||
@@ -210,8 +206,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
configurePool(tunnel);
|
||||
|
||||
if (open && listenerReady) {
|
||||
if (openNow)
|
||||
l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
|
||||
@@ -224,37 +218,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* build and configure the pool handling accept()ed but not yet
|
||||
* established connections
|
||||
*
|
||||
*/
|
||||
private void configurePool(I2PTunnel tunnel) {
|
||||
//_waitingSockets = new ArrayList(4);
|
||||
|
||||
Properties opts = tunnel.getClientOptions();
|
||||
String maxWait = opts.getProperty(PROP_MAX_WAIT_TIME, DEFAULT_MAX_WAIT_TIME+"");
|
||||
try {
|
||||
_maxWaitTime = Integer.parseInt(maxWait);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_maxWaitTime = DEFAULT_MAX_WAIT_TIME;
|
||||
}
|
||||
|
||||
String numBuild = opts.getProperty(PROP_NUM_CONNECTION_BUILDERS, DEFAULT_NUM_CONNECTION_BUILDERS+"");
|
||||
try {
|
||||
_numConnectionBuilders = Integer.parseInt(numBuild);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_numConnectionBuilders = DEFAULT_NUM_CONNECTION_BUILDERS;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _numConnectionBuilders; i++) {
|
||||
String name = "ClientBuilder" + _clientId + '.' + i;
|
||||
I2PAppThread b = new I2PAppThread(new TunnelConnectionBuilder(), name);
|
||||
b.setDaemon(true);
|
||||
b.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the this.sockMgr field if it is null, or if we want a new one
|
||||
*
|
||||
@@ -321,6 +284,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
* badly that we cant create a socketManager
|
||||
*/
|
||||
protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel, String pkf) {
|
||||
// shadows instance _log
|
||||
Log _log = tunnel.getContext().logManager().getLog(I2PTunnelClientBase.class);
|
||||
if (socketManager != null) {
|
||||
I2PSession s = socketManager.getSession();
|
||||
if ( (s == null) || (s.isClosed()) ) {
|
||||
@@ -378,6 +343,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
* badly that we cant create a socketManager
|
||||
*/
|
||||
protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel, String pkf, Logging log) {
|
||||
// shadows instance _log
|
||||
Log _log = tunnel.getContext().logManager().getLog(I2PTunnelClientBase.class);
|
||||
Properties props = new Properties();
|
||||
props.putAll(tunnel.getClientOptions());
|
||||
int portNum = 7654;
|
||||
@@ -537,7 +504,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
synchronized (_waitingSockets) { _waitingSockets.notifyAll(); }
|
||||
return;
|
||||
}
|
||||
ss = new ServerSocket(localPort, 0, addr);
|
||||
@@ -566,12 +532,9 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
while (open) {
|
||||
Socket s = ss.accept();
|
||||
long before = System.currentTimeMillis();
|
||||
manageConnection(s);
|
||||
long total = System.currentTimeMillis() - before;
|
||||
_context.statManager().addRateData("i2ptunnel.client.manageTime", total, total);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
if (open) {
|
||||
@@ -586,9 +549,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
synchronized (_waitingSockets) {
|
||||
_waitingSockets.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -598,24 +558,38 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
*/
|
||||
protected void manageConnection(Socket s) {
|
||||
if (s == null) return;
|
||||
if (_numConnectionBuilders <= 0) {
|
||||
new I2PAppThread(new BlockingRunner(s), "Clinet run").start();
|
||||
return;
|
||||
try {
|
||||
_executor.execute(new BlockingRunner(s));
|
||||
} catch (RejectedExecutionException ree) {
|
||||
// should never happen, we have an unbounded pool and never stop the executor
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
if (_maxWaitTime > 0)
|
||||
SimpleScheduler.getInstance().addEvent(new CloseEvent(s), _maxWaitTime);
|
||||
}
|
||||
|
||||
synchronized (_waitingSockets) {
|
||||
_waitingSockets.add(s);
|
||||
_waitingSockets.notifyAll();
|
||||
/**
|
||||
* Not really needed for now but in case we want to add some hooks like afterExecute().
|
||||
*/
|
||||
private static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
public CustomThreadPoolExecutor() {
|
||||
super(0, Integer.MAX_VALUE, HANDLER_KEEPALIVE_MS, TimeUnit.MILLISECONDS,
|
||||
new SynchronousQueue(), new CustomThreadFactory());
|
||||
}
|
||||
}
|
||||
|
||||
/** just to set the name and set Daemon */
|
||||
private static class CustomThreadFactory implements ThreadFactory {
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread rv = Executors.defaultThreadFactory().newThread(r);
|
||||
rv.setName("I2PTunnel Client Runner " + (++_executorThreadCount));
|
||||
rv.setDaemon(true);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking runner, used during the connection establishment whenever we
|
||||
* are not using the queued builders.
|
||||
*
|
||||
* Blocking runner, used during the connection establishment
|
||||
*/
|
||||
private class BlockingRunner implements Runnable {
|
||||
private Socket _s;
|
||||
@@ -625,32 +599,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and close the socket from the waiting list, if it is still there.
|
||||
*
|
||||
*/
|
||||
private class CloseEvent implements SimpleTimer.TimedEvent {
|
||||
private Socket _s;
|
||||
public CloseEvent(Socket s) { _s = s; }
|
||||
public void timeReached() {
|
||||
int remaining = 0;
|
||||
boolean stillWaiting = false;
|
||||
synchronized (_waitingSockets) {
|
||||
stillWaiting = _waitingSockets.remove(_s);
|
||||
remaining = _waitingSockets.size();
|
||||
}
|
||||
if (stillWaiting) {
|
||||
try { _s.close(); } catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_context.statManager().addRateData("i2ptunnel.client.closeBacklog", remaining, 0);
|
||||
_log.info("Closed a waiting socket because of backlog");
|
||||
}
|
||||
} else {
|
||||
_context.statManager().addRateData("i2ptunnel.client.closeNoBacklog", remaining, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean close(boolean forced) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("close() called: forced = " + forced + " open = " + open + " sockMgr = " + sockMgr);
|
||||
@@ -688,7 +636,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
//l.log("Client closed.");
|
||||
}
|
||||
|
||||
synchronized (_waitingSockets) { _waitingSockets.notifyAll(); }
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -696,40 +643,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
try {
|
||||
s.close();
|
||||
} catch (IOException ex) {
|
||||
_log.error("Could not close socket", ex);
|
||||
//_log.error("Could not close socket", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pool runner pulling sockets off the waiting list and pushing them
|
||||
* through clientConnectionRun. This dies when the I2PTunnel instance
|
||||
* is closed.
|
||||
*
|
||||
*/
|
||||
private class TunnelConnectionBuilder implements Runnable {
|
||||
public void run() {
|
||||
Socket s = null;
|
||||
while (open) {
|
||||
try {
|
||||
synchronized (_waitingSockets) {
|
||||
if (_waitingSockets.isEmpty())
|
||||
_waitingSockets.wait();
|
||||
else
|
||||
s = (Socket)_waitingSockets.remove(0);
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
|
||||
if (s != null) {
|
||||
long before = System.currentTimeMillis();
|
||||
clientConnectionRun(s);
|
||||
long total = System.currentTimeMillis() - before;
|
||||
_context.statManager().addRateData("i2ptunnel.client.buildRunTime", total, 0);
|
||||
}
|
||||
s = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage a connection in a separate thread. This only works if
|
||||
* you do not override manageConnection()
|
||||
|
||||
@@ -58,7 +58,6 @@ import net.i2p.util.Log;
|
||||
* @author zzz a stripped-down I2PTunnelHTTPClient
|
||||
*/
|
||||
public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements Runnable {
|
||||
private static final Log _log = new Log(I2PTunnelConnectClient.class);
|
||||
|
||||
private final static byte[] ERR_DESTINATION_UNKNOWN =
|
||||
("HTTP/1.1 503 Service Unavailable\r\n"+
|
||||
@@ -340,8 +339,8 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
|
||||
_requestId = id;
|
||||
}
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Timeout occured requesting " + _target);
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Timeout occured requesting " + _target);
|
||||
handleConnectClientException(new RuntimeException("Timeout"), _out,
|
||||
_target, _usingProxy, _wwwProxy, _requestId);
|
||||
closeSocket(_socket);
|
||||
|
||||
@@ -11,7 +11,6 @@ import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelHTTPBidirServer extends I2PTunnelHTTPServer {
|
||||
private final static Log log = new Log(I2PTunnelHTTPBidirServer.class);
|
||||
|
||||
public I2PTunnelHTTPBidirServer(InetAddress host, int port, int proxyport, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host, port, privData, spoofHost, l, notifyThis, tunnel);
|
||||
|
||||
@@ -61,7 +61,6 @@ import net.i2p.util.Translate;
|
||||
*
|
||||
*/
|
||||
public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runnable {
|
||||
private static final Log _log = new Log(I2PTunnelHTTPClient.class);
|
||||
|
||||
private HashMap addressHelpers = new HashMap();
|
||||
|
||||
@@ -894,15 +893,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
_requestId = id;
|
||||
}
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Timeout occured requesting " + _target);
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Timeout occured requesting " + _target);
|
||||
handleHTTPClientException(new RuntimeException("Timeout"), _out,
|
||||
_target, _usingProxy, _wwwProxy, _requestId);
|
||||
closeSocket(_socket);
|
||||
}
|
||||
}
|
||||
|
||||
private static String DEFAULT_JUMP_SERVERS =
|
||||
public static final String DEFAULT_JUMP_SERVERS =
|
||||
"http://i2host.i2p/cgi-bin/i2hostjump?," +
|
||||
"http://stats.i2p/cgi-bin/jump.cgi?a=," +
|
||||
"http://i2jump.i2p/";
|
||||
@@ -940,8 +939,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
|
||||
// Skip jump servers we don't know
|
||||
String jumphost = jurl.substring(7); // "http://"
|
||||
jumphost = jumphost.substring(0, jumphost.indexOf('/'));
|
||||
Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(jumphost);
|
||||
if (dest == null) continue;
|
||||
if (!jumphost.endsWith(".i2p"))
|
||||
continue;
|
||||
if (!jumphost.endsWith(".b32.i2p")) {
|
||||
Destination dest = I2PAppContext.getGlobalContext().namingService().lookup(jumphost);
|
||||
if (dest == null) continue;
|
||||
}
|
||||
|
||||
out.write("<br><a href=\"".getBytes());
|
||||
out.write(jurl.getBytes());
|
||||
|
||||
@@ -25,7 +25,7 @@ import net.i2p.util.Log;
|
||||
* @since 0.8.2
|
||||
*/
|
||||
public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implements Runnable {
|
||||
private static final Log _log = new Log(I2PTunnelHTTPClientBase.class);
|
||||
|
||||
protected final List<String> _proxyList;
|
||||
|
||||
protected final static byte[] ERR_NO_OUTPROXY =
|
||||
|
||||
@@ -31,7 +31,7 @@ import net.i2p.data.Base32;
|
||||
*
|
||||
*/
|
||||
public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
private final static Log _log = new Log(I2PTunnelHTTPServer.class);
|
||||
|
||||
/** what Host: should we seem to be to the webserver? */
|
||||
private String _spoofHost;
|
||||
private static final String HASH_HEADER = "X-I2P-DestHash";
|
||||
@@ -40,6 +40,20 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
private static final String[] CLIENT_SKIPHEADERS = {HASH_HEADER, DEST64_HEADER, DEST32_HEADER};
|
||||
private static final String SERVER_HEADER = "Server";
|
||||
private static final String[] SERVER_SKIPHEADERS = {SERVER_HEADER};
|
||||
private static final long HEADER_TIMEOUT = 60*1000;
|
||||
|
||||
private final static byte[] ERR_UNAVAILABLE =
|
||||
("HTTP/1.1 503 Service Unavailable\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
"Cache-control: no-cache\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"Proxy-Connection: close\r\n"+
|
||||
"\r\n"+
|
||||
"<html><head><title>503 Service Unavailable<title></head>\n"+
|
||||
"<body><h2>503 Service Unavailable</h2>\n" +
|
||||
"<p>This I2P eepsite is unavailable. It may be down or undergoing maintenance.</p>\n" +
|
||||
"</body></html>")
|
||||
.getBytes();
|
||||
|
||||
public I2PTunnelHTTPServer(InetAddress host, int port, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host, port, privData, l, notifyThis, tunnel);
|
||||
@@ -73,8 +87,9 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
//local is fast, so synchronously. Does not need that many
|
||||
//threads.
|
||||
try {
|
||||
// give them 5 seconds to send in the HTTP request
|
||||
socket.setReadTimeout(5*1000);
|
||||
// The headers _should_ be in the first packet, but
|
||||
// may not be, depending on the client-side options
|
||||
socket.setReadTimeout(HEADER_TIMEOUT);
|
||||
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
@@ -124,19 +139,30 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
|
||||
if (allowGZIP && useGZIP) {
|
||||
I2PAppThread req = new I2PAppThread(
|
||||
new CompressedRequestor(s, socket, modifiedHeader, getTunnel().getContext()),
|
||||
new CompressedRequestor(s, socket, modifiedHeader, getTunnel().getContext(), _log),
|
||||
Thread.currentThread().getName()+".hc");
|
||||
req.start();
|
||||
} else {
|
||||
new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(), null);
|
||||
}
|
||||
|
||||
long afterHandle = getTunnel().getContext().clock().now();
|
||||
long timeToHandle = afterHandle - afterAccept;
|
||||
getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle, 0);
|
||||
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort +
|
||||
" [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
} catch (SocketException ex) {
|
||||
try {
|
||||
// Send a 503, so the user doesn't get an HTTP Proxy error message
|
||||
// and blame his router or the network.
|
||||
socket.getOutputStream().write(ERR_UNAVAILABLE);
|
||||
} catch (IOException ioe) {}
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error while closing the received i2p con", ex);
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error connecting to HTTP server " + remoteHost + ':' + remotePort, ex);
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
socket.close();
|
||||
@@ -150,25 +176,24 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("OOM in HTTP server", oom);
|
||||
}
|
||||
|
||||
long afterHandle = getTunnel().getContext().clock().now();
|
||||
long timeToHandle = afterHandle - afterAccept;
|
||||
getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle, 0);
|
||||
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("Took a while to handle the request [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
}
|
||||
|
||||
private static class CompressedRequestor implements Runnable {
|
||||
private Socket _webserver;
|
||||
private I2PSocket _browser;
|
||||
private String _headers;
|
||||
private I2PAppContext _ctx;
|
||||
public CompressedRequestor(Socket webserver, I2PSocket browser, String headers, I2PAppContext ctx) {
|
||||
private final Socket _webserver;
|
||||
private final I2PSocket _browser;
|
||||
private final String _headers;
|
||||
private final I2PAppContext _ctx;
|
||||
// shadows _log in super()
|
||||
private final Log _log;
|
||||
|
||||
public CompressedRequestor(Socket webserver, I2PSocket browser, String headers, I2PAppContext ctx, Log log) {
|
||||
_webserver = webserver;
|
||||
_browser = browser;
|
||||
_headers = headers;
|
||||
_ctx = ctx;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Compressed requestor running");
|
||||
@@ -183,7 +208,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
_log.info("request headers: " + _headers);
|
||||
serverout.write(_headers.getBytes());
|
||||
browserin = _browser.getInputStream();
|
||||
I2PAppThread sender = new I2PAppThread(new Sender(serverout, browserin, "server: browser to server"), Thread.currentThread().getName() + "hcs");
|
||||
I2PAppThread sender = new I2PAppThread(new Sender(serverout, browserin, "server: browser to server", _log), Thread.currentThread().getName() + "hcs");
|
||||
sender.start();
|
||||
|
||||
browserout = _browser.getOutputStream();
|
||||
@@ -214,7 +239,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
String modifiedHeaders = formatHeaders(headers, command);
|
||||
compressedOut.write(modifiedHeaders.getBytes());
|
||||
|
||||
Sender s = new Sender(compressedOut, serverin, "server: server to browser");
|
||||
Sender s = new Sender(compressedOut, serverin, "server: server to browser", _log);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Before pumping the compressed response");
|
||||
s.run(); // same thread
|
||||
@@ -233,14 +258,19 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
}
|
||||
|
||||
private static class Sender implements Runnable {
|
||||
private OutputStream _out;
|
||||
private InputStream _in;
|
||||
private String _name;
|
||||
public Sender(OutputStream out, InputStream in, String name) {
|
||||
private final OutputStream _out;
|
||||
private final InputStream _in;
|
||||
private final String _name;
|
||||
// shadows _log in super()
|
||||
private final Log _log;
|
||||
|
||||
public Sender(OutputStream out, InputStream in, String name, Log log) {
|
||||
_out = out;
|
||||
_in = in;
|
||||
_name = name;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(_name + ": Begin sending");
|
||||
@@ -277,16 +307,16 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
protected boolean shouldCompress() { return true; }
|
||||
@Override
|
||||
protected void finishHeaders() throws IOException {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Including x-i2p-gzip as the content encoding in the response");
|
||||
//if (_log.shouldLog(Log.INFO))
|
||||
// _log.info("Including x-i2p-gzip as the content encoding in the response");
|
||||
out.write("Content-encoding: x-i2p-gzip\r\n".getBytes());
|
||||
super.finishHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beginProcessing() throws IOException {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Beginning compression processing");
|
||||
//if (_log.shouldLog(Log.INFO))
|
||||
// _log.info("Beginning compression processing");
|
||||
//out.flush();
|
||||
_gzipOut = new InternalGZIPOutputStream(out);
|
||||
out = _gzipOut;
|
||||
@@ -352,8 +382,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
boolean ok = DataHelper.readLine(in, command);
|
||||
if (!ok) throw new IOException("EOF reached while reading the HTTP command [" + command.toString() + "]");
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Read the http command [" + command.toString() + "]");
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Read the http command [" + command.toString() + "]");
|
||||
|
||||
// FIXME we probably don't need or want this in the outgoing direction
|
||||
int trimmed = 0;
|
||||
@@ -409,8 +439,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
}
|
||||
|
||||
headers.setProperty(name, value);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Read the header [" + name + "] = [" + value + "]");
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Read the header [" + name + "] = [" + value + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ import net.i2p.util.Log;
|
||||
*/
|
||||
public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable {
|
||||
|
||||
private static final Log _log = new Log(I2PTunnelIRCClient.class);
|
||||
|
||||
/** used to assign unique IDs to the threads / clients. no logic or functionality */
|
||||
private static volatile long __clientId = 0;
|
||||
|
||||
@@ -130,6 +128,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
private Socket local;
|
||||
private I2PSocket remote;
|
||||
private StringBuffer expectedPong;
|
||||
// shadows _log in super()
|
||||
private final Log _log = new Log(I2PTunnelIRCClient.class);
|
||||
|
||||
public IrcInboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) {
|
||||
local=_local;
|
||||
@@ -207,6 +207,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
private Socket local;
|
||||
private I2PSocket remote;
|
||||
private StringBuffer expectedPong;
|
||||
// shadows _log in super()
|
||||
private final Log _log = new Log(I2PTunnelIRCClient.class);
|
||||
|
||||
public IrcOutboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) {
|
||||
local=_local;
|
||||
@@ -308,7 +310,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
try { command = field[idx++]; }
|
||||
catch (IndexOutOfBoundsException ioobe) // wtf, server sent borked command?
|
||||
{
|
||||
_log.warn("Dropping defective message: index out of bounds while extracting command.");
|
||||
//_log.warn("Dropping defective message: index out of bounds while extracting command.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -431,13 +433,13 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
rv = "PING " + field[1];
|
||||
expectedPong.append("PONG ").append(field[2]).append(" :").append(field[1]); // PONG serverLocation nonce
|
||||
} else {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("IRC client sent a PING we don't understand, filtering it (\"" + s + "\")");
|
||||
//if (_log.shouldLog(Log.ERROR))
|
||||
// _log.error("IRC client sent a PING we don't understand, filtering it (\"" + s + "\")");
|
||||
rv = null;
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("sending ping [" + rv + "], waiting for [" + expectedPong + "] orig was [" + s + "]");
|
||||
//if (_log.shouldLog(Log.WARN))
|
||||
// _log.warn("sending ping [" + rv + "], waiting for [" + expectedPong + "] orig was [" + s + "]");
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -61,9 +61,7 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
public static final String PROP_WEBIRC_SPOOF_IP_DEFAULT="127.0.0.1";
|
||||
public static final String PROP_HOSTNAME="ircserver.fakeHostname";
|
||||
public static final String PROP_HOSTNAME_DEFAULT="%f.b32.i2p";
|
||||
|
||||
private static final Log _log = new Log(I2PTunnelIRCServer.class);
|
||||
|
||||
private static final long HEADER_TIMEOUT = 60*1000;
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
||||
@@ -108,8 +106,9 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
try {
|
||||
String modifiedRegistration;
|
||||
if(!this.method.equals("webirc")) {
|
||||
// give them 15 seconds to send in the request
|
||||
socket.setReadTimeout(15*1000);
|
||||
// The headers _should_ be in the first packet, but
|
||||
// may not be, depending on the client-side options
|
||||
socket.setReadTimeout(HEADER_TIMEOUT);
|
||||
InputStream in = socket.getInputStream();
|
||||
modifiedRegistration = filterRegistration(in, cloakDest(socket.getPeerDestination()));
|
||||
socket.setReadTimeout(readTimeout);
|
||||
@@ -126,12 +125,12 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(), null);
|
||||
} catch (SocketException ex) {
|
||||
// TODO send the equivalent of a 503?
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error while closing the received i2p con", ex);
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error connecting to IRC server " + remoteHost + ':' + remotePort, ex);
|
||||
} catch (IOException ex) {
|
||||
try {
|
||||
socket.close();
|
||||
@@ -181,8 +180,8 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
if (++lineCount > 10)
|
||||
throw new IOException("Too many lines before USER or SERVER, giving up");
|
||||
s = s.trim();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Got line: " + s);
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Got line: " + s);
|
||||
|
||||
String field[]=s.split(" ",5);
|
||||
String command;
|
||||
@@ -214,8 +213,8 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
if ("SERVER".equalsIgnoreCase(command))
|
||||
break;
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("All done, sending: " + buf.toString());
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("All done, sending: " + buf.toString());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,12 @@ import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
@@ -30,8 +36,7 @@ import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
|
||||
private final static Log _log = new Log(I2PTunnelServer.class);
|
||||
|
||||
protected final Log _log;
|
||||
protected I2PSocketManager sockMgr;
|
||||
protected I2PServerSocket i2pss;
|
||||
|
||||
@@ -48,12 +53,17 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
/** default timeout to 3 minutes - override if desired */
|
||||
protected long readTimeout = DEFAULT_READ_TIMEOUT;
|
||||
|
||||
private static final boolean DEFAULT_USE_POOL = false;
|
||||
/** do we use threads? default true (ignored for standard servers, always false) */
|
||||
private static final String PROP_USE_POOL = "i2ptunnel.usePool";
|
||||
private static final boolean DEFAULT_USE_POOL = true;
|
||||
protected static volatile long __serverId = 0;
|
||||
/** max number of threads - this many slowlorisses will DOS this server, but too high could OOM the JVM */
|
||||
private static final String PROP_HANDLER_COUNT = "i2ptunnel.blockingHandlerCount";
|
||||
private static final int DEFAULT_HANDLER_COUNT = 10;
|
||||
|
||||
|
||||
private static final int DEFAULT_HANDLER_COUNT = 65;
|
||||
/** min number of threads */
|
||||
private static final int MIN_HANDLERS = 0;
|
||||
/** how long to wait before dropping an idle thread */
|
||||
private static final long HANDLER_KEEPALIVE_MS = 30*1000;
|
||||
|
||||
protected I2PTunnelTask task = null;
|
||||
protected boolean bidir = false;
|
||||
@@ -67,8 +77,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
*/
|
||||
public I2PTunnelServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super("Server at " + host + ':' + port, notifyThis, tunnel);
|
||||
_log = tunnel.getContext().logManager().getLog(getClass());
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(privData));
|
||||
SetUsePool(tunnel);
|
||||
init(host, port, bais, privData, l);
|
||||
}
|
||||
|
||||
@@ -79,7 +89,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
public I2PTunnelServer(InetAddress host, int port, File privkey, String privkeyname, Logging l,
|
||||
EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super("Server at " + host + ':' + port, notifyThis, tunnel);
|
||||
SetUsePool(tunnel);
|
||||
_log = tunnel.getContext().logManager().getLog(getClass());
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(privkey);
|
||||
@@ -99,19 +109,10 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
*/
|
||||
public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super("Server at " + host + ':' + port, notifyThis, tunnel);
|
||||
SetUsePool(tunnel);
|
||||
_log = tunnel.getContext().logManager().getLog(getClass());
|
||||
init(host, port, privData, privkeyname, l);
|
||||
}
|
||||
|
||||
|
||||
private void SetUsePool(I2PTunnel Tunnel) {
|
||||
String usePool = Tunnel.getClientOptions().getProperty("i2ptunnel.usePool");
|
||||
if (usePool != null)
|
||||
_usePool = "true".equalsIgnoreCase(usePool);
|
||||
else
|
||||
_usePool = DEFAULT_USE_POOL;
|
||||
}
|
||||
|
||||
private static final int RETRY_DELAY = 20*1000;
|
||||
private static final int MAX_RETRIES = 4;
|
||||
|
||||
@@ -143,6 +144,16 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
// extending classes default to threaded, but for a standard server, we can't get slowlorissed
|
||||
_usePool = !getClass().equals(I2PTunnelServer.class);
|
||||
if (_usePool) {
|
||||
String usePool = getTunnel().getClientOptions().getProperty(PROP_USE_POOL);
|
||||
if (usePool != null)
|
||||
_usePool = "true".equalsIgnoreCase(usePool);
|
||||
else
|
||||
_usePool = DEFAULT_USE_POOL;
|
||||
}
|
||||
|
||||
// Todo: Can't stop a tunnel from the UI while it's in this loop (no session yet)
|
||||
int retries = 0;
|
||||
while (sockMgr == null) {
|
||||
@@ -199,8 +210,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
*
|
||||
*/
|
||||
public void startRunning() {
|
||||
Thread t = new I2PAppThread(this);
|
||||
t.setName("Server " + (++__serverId));
|
||||
Thread t = new I2PAppThread(this, "Server " + remoteHost + ':' + remotePort, true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
@@ -236,7 +246,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
l.log("Stopping tunnels for server at " + getTunnel().listenHost + ':' + this.remotePort);
|
||||
l.log("Stopping tunnels for server at " + this.remoteHost + ':' + this.remotePort);
|
||||
try {
|
||||
if (i2pss != null) i2pss.close();
|
||||
getTunnel().removeSession(sockMgr.getSession());
|
||||
@@ -259,67 +269,106 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
rv = Integer.parseInt(cnt);
|
||||
if (rv <= 0)
|
||||
rv = DEFAULT_HANDLER_COUNT;
|
||||
} catch (NumberFormatException nfe) {
|
||||
rv = DEFAULT_HANDLER_COUNT;
|
||||
}
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* If usePool is set, this starts the executor pool.
|
||||
* Then, do the accept() loop, and either
|
||||
* hands each I2P socket to the executor or runs it in-line.
|
||||
*/
|
||||
public void run() {
|
||||
if (shouldUsePool()) {
|
||||
I2PServerSocket i2pS_S = sockMgr.getServerSocket();
|
||||
int handlers = getHandlerCount();
|
||||
for (int i = 0; i < handlers; i++) {
|
||||
I2PAppThread handler = new I2PAppThread(new Handler(i2pS_S), "Handle Server " + i);
|
||||
handler.start();
|
||||
}
|
||||
} else {
|
||||
I2PServerSocket i2pS_S = sockMgr.getServerSocket();
|
||||
while (true) {
|
||||
try {
|
||||
final I2PSocket i2ps = i2pS_S.accept();
|
||||
if (i2ps == null) throw new I2PException("I2PServerSocket closed");
|
||||
new I2PAppThread(new Runnable() { public void run() { blockingHandle(i2ps); } }).start();
|
||||
} catch (I2PException ipe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting - KILLING THE TUNNEL SERVER", ipe);
|
||||
return;
|
||||
} catch (ConnectException ce) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting", ce);
|
||||
// not killing the server..
|
||||
} catch(SocketTimeoutException ste) {
|
||||
// ignored, we never set the timeout
|
||||
I2PServerSocket i2pS_S = sockMgr.getServerSocket();
|
||||
ThreadPoolExecutor executor = null;
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
if (_usePool)
|
||||
_log.warn("Starting executor with " + getHandlerCount() + " threads max");
|
||||
else
|
||||
_log.warn("Threads disabled, running blockingHandles inline");
|
||||
}
|
||||
if (_usePool) {
|
||||
executor = new CustomThreadPoolExecutor(getHandlerCount(), "ServerHandler pool " + remoteHost + ':' + remotePort);
|
||||
}
|
||||
while (open) {
|
||||
try {
|
||||
final I2PSocket i2ps = i2pS_S.accept();
|
||||
if (i2ps == null) throw new I2PException("I2PServerSocket closed");
|
||||
if (_usePool) {
|
||||
try {
|
||||
executor.execute(new Handler(i2ps));
|
||||
} catch (RejectedExecutionException ree) {
|
||||
try {
|
||||
i2ps.close();
|
||||
} catch (IOException ioe) {}
|
||||
if (open && _log.shouldLog(Log.ERROR))
|
||||
_log.error("ServerHandler queue full for " + remoteHost + ':' + remotePort +
|
||||
"; increase " + PROP_HANDLER_COUNT + '?', ree);
|
||||
}
|
||||
} else {
|
||||
// use only for standard servers that can't get slowlorissed! Not for http or irc
|
||||
blockingHandle(i2ps);
|
||||
}
|
||||
} catch (I2PException ipe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting - KILLING THE TUNNEL SERVER", ipe);
|
||||
return;
|
||||
} catch (ConnectException ce) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error accepting", ce);
|
||||
// not killing the server..
|
||||
try {
|
||||
Thread.currentThread().sleep(500);
|
||||
} catch (InterruptedException ie) {}
|
||||
} catch(SocketTimeoutException ste) {
|
||||
// ignored, we never set the timeout
|
||||
}
|
||||
}
|
||||
if (executor != null)
|
||||
executor.shutdownNow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Not really needed for now but in case we want to add some hooks like afterExecute().
|
||||
*/
|
||||
private static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
public CustomThreadPoolExecutor(int max, String name) {
|
||||
super(MIN_HANDLERS, max, HANDLER_KEEPALIVE_MS, TimeUnit.MILLISECONDS,
|
||||
new SynchronousQueue(), new CustomThreadFactory(name));
|
||||
}
|
||||
}
|
||||
|
||||
/** just to set the name and set Daemon */
|
||||
private static class CustomThreadFactory implements ThreadFactory {
|
||||
private String _name;
|
||||
|
||||
public CustomThreadFactory(String name) {
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread rv = Executors.defaultThreadFactory().newThread(r);
|
||||
rv.setName(_name);
|
||||
rv.setDaemon(true);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldUsePool() { return _usePool; }
|
||||
|
||||
/**
|
||||
* minor thread pool to pull off the accept() concurrently. there are still lots
|
||||
* (and lots) of wasted threads within the I2PTunnelRunner, but its a start
|
||||
*
|
||||
* Run the blockingHandler.
|
||||
*/
|
||||
private class Handler implements Runnable {
|
||||
private I2PServerSocket _serverSocket;
|
||||
public Handler(I2PServerSocket serverSocket) {
|
||||
_serverSocket = serverSocket;
|
||||
private I2PSocket _i2ps;
|
||||
|
||||
public Handler(I2PSocket socket) {
|
||||
_i2ps = socket;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (open) {
|
||||
try {
|
||||
blockingHandle(_serverSocket.accept());
|
||||
} catch (I2PException ex) {
|
||||
_log.error("Error while waiting for I2PConnections", ex);
|
||||
return;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while waiting for I2PConnections", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
blockingHandle(_i2ps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,20 +384,21 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
afterSocket = I2PAppContext.getGlobalContext().clock().now();
|
||||
new I2PTunnelRunner(s, socket, slock, null, null);
|
||||
|
||||
long afterHandle = I2PAppContext.getGlobalContext().clock().now();
|
||||
long timeToHandle = afterHandle - afterAccept;
|
||||
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
|
||||
_log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort +
|
||||
" [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
} catch (SocketException ex) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error while closing the received i2p con", ex);
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error connecting to server " + remoteHost + ':' + remotePort, ex);
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while waiting for I2PConnections", ex);
|
||||
}
|
||||
|
||||
long afterHandle = I2PAppContext.getGlobalContext().clock().now();
|
||||
long timeToHandle = afterHandle - afterAccept;
|
||||
if (timeToHandle > 1000)
|
||||
_log.warn("Took a while to handle the request [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -259,10 +259,9 @@ public class TunnelController implements Logging {
|
||||
|
||||
/*
|
||||
* Streamr client is a UDP server, use the listenPort field for targetPort
|
||||
* and the listenOnInterface field for the targetHost
|
||||
*/
|
||||
private void startStreamrClient() {
|
||||
String targetHost = getListenOnInterface();
|
||||
String targetHost = getTargetHost();
|
||||
String targetPort = getListenPort();
|
||||
String dest = getTargetDestination();
|
||||
_tunnel.runStreamrClient(new String[] { targetHost, targetPort, dest }, this);
|
||||
@@ -270,10 +269,9 @@ public class TunnelController implements Logging {
|
||||
|
||||
/**
|
||||
* Streamr server is a UDP client, use the targetPort field for listenPort
|
||||
* and the targetHost field for the listenOnInterface
|
||||
*/
|
||||
private void startStreamrServer() {
|
||||
String listenOn = getTargetHost();
|
||||
String listenOn = getListenOnInterface();
|
||||
if ( (listenOn != null) && (listenOn.length() > 0) ) {
|
||||
_tunnel.runListenOn(new String[] { listenOn }, this);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import net.i2p.util.Log;
|
||||
*/
|
||||
public class I2PSOCKSIRCTunnel extends I2PSOCKSTunnel {
|
||||
|
||||
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(I2PSOCKSIRCTunnel.class);
|
||||
private static int __clientId = 0;
|
||||
|
||||
/** @param pkf private key file name or null for transient key */
|
||||
|
||||
@@ -26,7 +26,6 @@ import net.i2p.util.Log;
|
||||
|
||||
public class I2PSOCKSTunnel extends I2PTunnelClientBase {
|
||||
|
||||
private static final Log _log = new Log(I2PSOCKSTunnel.class);
|
||||
private HashMap<String, List<String>> proxies = null; // port# + "" or "default" -> hostname list
|
||||
protected Destination outProxyDest = null;
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ import net.i2p.util.Log;
|
||||
*/
|
||||
public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements Source, Sink {
|
||||
|
||||
private static final Log _log = new Log(I2PTunnelUDPClientBase.class);
|
||||
protected I2PAppContext _context;
|
||||
protected Logging l;
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sink {
|
||||
|
||||
private final static Log _log = new Log(I2PTunnelUDPServerBase.class);
|
||||
private final Log _log;
|
||||
|
||||
private final Object lock = new Object();
|
||||
protected Object slock = new Object();
|
||||
@@ -73,6 +73,7 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin
|
||||
public I2PTunnelUDPServerBase(boolean verify, File privkey, String privkeyname, Logging l,
|
||||
EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super("UDPServer <- " + privkeyname, notifyThis, tunnel);
|
||||
_log = tunnel.getContext().logManager().getLog(I2PTunnelUDPServerBase.class);
|
||||
FileInputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(privkey);
|
||||
|
||||
@@ -12,15 +12,18 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.PrivateKeyFile;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.i2ptunnel.TunnelControllerGroup;
|
||||
import net.i2p.util.Addresses;
|
||||
|
||||
/**
|
||||
* Ugly little accessor for the edit page
|
||||
@@ -171,14 +174,23 @@ public class EditBean extends IndexBean {
|
||||
return getProperty(tunnel, "i2cp.leaseSetKey", "");
|
||||
}
|
||||
|
||||
public boolean getAccess(int tunnel) {
|
||||
return getBooleanProperty(tunnel, "i2cp.enableAccessList");
|
||||
public String getAccessMode(int tunnel) {
|
||||
if (getBooleanProperty(tunnel, PROP_ENABLE_ACCESS_LIST))
|
||||
return "1";
|
||||
if (getBooleanProperty(tunnel, PROP_ENABLE_BLACKLIST))
|
||||
return "2";
|
||||
return "0";
|
||||
}
|
||||
|
||||
public String getAccessList(int tunnel) {
|
||||
return getProperty(tunnel, "i2cp.accessList", "").replace(",", "\n");
|
||||
}
|
||||
|
||||
public String getJumpList(int tunnel) {
|
||||
return getProperty(tunnel, I2PTunnelHTTPClient.PROP_JUMP_SERVERS,
|
||||
I2PTunnelHTTPClient.DEFAULT_JUMP_SERVERS).replace(",", "\n");
|
||||
}
|
||||
|
||||
public boolean getClose(int tunnel) {
|
||||
return getBooleanProperty(tunnel, "i2cp.closeOnIdle");
|
||||
}
|
||||
@@ -234,6 +246,35 @@ public class EditBean extends IndexBean {
|
||||
return getProperty(tunnel, I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW, "");
|
||||
}
|
||||
|
||||
/** all of these are @since 0.8.3 */
|
||||
public String getLimitMinute(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_CONNS_MIN, "0");
|
||||
}
|
||||
|
||||
public String getLimitHour(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_CONNS_HOUR, "0");
|
||||
}
|
||||
|
||||
public String getLimitDay(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_CONNS_DAY, "0");
|
||||
}
|
||||
|
||||
public String getTotalMinute(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_MIN, "0");
|
||||
}
|
||||
|
||||
public String getTotalHour(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_HOUR, "0");
|
||||
}
|
||||
|
||||
public String getTotalDay(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_DAY, "0");
|
||||
}
|
||||
|
||||
public String getMaxStreams(int tunnel) {
|
||||
return getProperty(tunnel, PROP_MAX_STREAMS, "0");
|
||||
}
|
||||
|
||||
private int getProperty(int tunnel, String prop, int def) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null) {
|
||||
@@ -270,7 +311,19 @@ public class EditBean extends IndexBean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public boolean isRouterContext() {
|
||||
return _context.isRouterContext();
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public Set<String> interfaceSet() {
|
||||
return Addresses.getAllAddresses();
|
||||
}
|
||||
|
||||
public String getI2CPHost(int tunnel) {
|
||||
if (_context.isRouterContext())
|
||||
return _("internal");
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getI2CPHost();
|
||||
@@ -279,6 +332,8 @@ public class EditBean extends IndexBean {
|
||||
}
|
||||
|
||||
public String getI2CPPort(int tunnel) {
|
||||
if (_context.isRouterContext())
|
||||
return _("internal");
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getI2CPPort();
|
||||
|
||||
@@ -24,6 +24,7 @@ import net.i2p.data.Certificate;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.PrivateKeyFile;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
|
||||
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
|
||||
import net.i2p.i2ptunnel.TunnelController;
|
||||
import net.i2p.i2ptunnel.TunnelControllerGroup;
|
||||
@@ -62,7 +63,6 @@ public class IndexBean {
|
||||
private String _proxyList;
|
||||
private String _port;
|
||||
private String _reachableBy;
|
||||
private String _reachableByOther;
|
||||
private String _targetDestination;
|
||||
private String _targetHost;
|
||||
private String _targetPort;
|
||||
@@ -431,10 +431,13 @@ public class IndexBean {
|
||||
|
||||
public String getClientInterface(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getListenOnInterface();
|
||||
else
|
||||
return "";
|
||||
if (tun != null) {
|
||||
if ("streamrclient".equals(tun.getType()))
|
||||
return tun.getTargetHost();
|
||||
else
|
||||
return tun.getListenOnInterface();
|
||||
} else
|
||||
return "127.0.0.1";
|
||||
}
|
||||
|
||||
public int getTunnelStatus(int tunnel) {
|
||||
@@ -477,11 +480,38 @@ public class IndexBean {
|
||||
return rv != null ? rv : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to see if it is ok to linkify getServerTarget()
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public boolean isServerTargetLinkValid(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
return tun != null &&
|
||||
"httpserver".equals(tun.getType()) &&
|
||||
tun.getTargetHost() != null &&
|
||||
tun.getTargetPort() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return valid host:port only if isServerTargetLinkValid() is true
|
||||
*/
|
||||
public String getServerTarget(int tunnel) {
|
||||
TunnelController tun = getController(tunnel);
|
||||
if (tun != null)
|
||||
return tun.getTargetHost() + ':' + tun.getTargetPort();
|
||||
else
|
||||
if (tun != null) {
|
||||
String host;
|
||||
if ("streamrserver".equals(tun.getType()))
|
||||
host = tun.getListenOnInterface();
|
||||
else
|
||||
host = tun.getTargetHost();
|
||||
String port = tun.getTargetPort();
|
||||
if (host == null)
|
||||
host = "<font color=\"red\">" + _("Host not set") + "</font>";
|
||||
else if (host.indexOf(':') >= 0)
|
||||
host = '[' + host + ']';
|
||||
if (port == null)
|
||||
port = "<font color=\"red\">" + _("Port not set") + "</font>";
|
||||
return host + ':' + port;
|
||||
} else
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -537,11 +567,11 @@ public class IndexBean {
|
||||
public void setDescription(String description) {
|
||||
_description = (description != null ? description.trim() : null);
|
||||
}
|
||||
/** I2CP host the router is on */
|
||||
/** I2CP host the router is on, ignored when in router context */
|
||||
public void setClientHost(String host) {
|
||||
_i2cpHost = (host != null ? host.trim() : null);
|
||||
}
|
||||
/** I2CP port the router is on */
|
||||
/** I2CP port the router is on, ignored when in router context */
|
||||
public void setClientport(String port) {
|
||||
_i2cpPort = (port != null ? port.trim() : null);
|
||||
}
|
||||
@@ -574,19 +604,11 @@ public class IndexBean {
|
||||
_port = (port != null ? port.trim() : null);
|
||||
}
|
||||
/**
|
||||
* what interface should this client/httpclient/ircclient listen on (unless
|
||||
* overridden by the setReachableByOther() field)
|
||||
* what interface should this client/httpclient/ircclient listen on
|
||||
*/
|
||||
public void setReachableBy(String reachableBy) {
|
||||
_reachableBy = (reachableBy != null ? reachableBy.trim() : null);
|
||||
}
|
||||
/**
|
||||
* If specified, defines the exact IP interface to listen for requests
|
||||
* on (in the case of client/httpclient/ircclient tunnels)
|
||||
*/
|
||||
public void setReachableByOther(String reachableByOther) {
|
||||
_reachableByOther = (reachableByOther != null ? reachableByOther.trim() : null);
|
||||
}
|
||||
/** What peer does this client tunnel point at */
|
||||
public void setTargetDestination(String dest) {
|
||||
_targetDestination = (dest != null ? dest.trim() : null);
|
||||
@@ -643,9 +665,17 @@ public class IndexBean {
|
||||
public void setEncrypt(String moo) {
|
||||
_booleanOptions.add("i2cp.encryptLeaseSet");
|
||||
}
|
||||
public void setAccess(String moo) {
|
||||
_booleanOptions.add("i2cp.enableAccessList");
|
||||
|
||||
protected static final String PROP_ENABLE_ACCESS_LIST = "i2cp.enableAccessList";
|
||||
protected static final String PROP_ENABLE_BLACKLIST = "i2cp.enableBlackList";
|
||||
|
||||
public void setAccessMode(String val) {
|
||||
if ("1".equals(val))
|
||||
_booleanOptions.add(PROP_ENABLE_ACCESS_LIST);
|
||||
else if ("2".equals(val))
|
||||
_booleanOptions.add(PROP_ENABLE_BLACKLIST);
|
||||
}
|
||||
|
||||
public void setDelayOpen(String moo) {
|
||||
_booleanOptions.add("i2cp.delayOpen");
|
||||
}
|
||||
@@ -671,10 +701,17 @@ public class IndexBean {
|
||||
if (val != null)
|
||||
_otherOptions.put("i2cp.leaseSetKey", val.trim());
|
||||
}
|
||||
|
||||
public void setAccessList(String val) {
|
||||
if (val != null)
|
||||
_otherOptions.put("i2cp.accessList", val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
|
||||
}
|
||||
|
||||
public void setJumpList(String val) {
|
||||
if (val != null)
|
||||
_otherOptions.put(I2PTunnelHTTPClient.PROP_JUMP_SERVERS, val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
|
||||
}
|
||||
|
||||
public void setCloseTime(String val) {
|
||||
if (val != null) {
|
||||
try {
|
||||
@@ -712,6 +749,50 @@ public class IndexBean {
|
||||
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW, s.trim());
|
||||
}
|
||||
|
||||
/** all of these are @since 0.8.3 */
|
||||
protected static final String PROP_MAX_CONNS_MIN = "i2p.streaming.maxConnsPerMinute";
|
||||
protected static final String PROP_MAX_CONNS_HOUR = "i2p.streaming.maxConnsPerHour";
|
||||
protected static final String PROP_MAX_CONNS_DAY = "i2p.streaming.maxConnsPerDay";
|
||||
protected static final String PROP_MAX_TOTAL_CONNS_MIN = "i2p.streaming.maxTotalConnsPerMinute";
|
||||
protected static final String PROP_MAX_TOTAL_CONNS_HOUR = "i2p.streaming.maxTotalConnsPerHour";
|
||||
protected static final String PROP_MAX_TOTAL_CONNS_DAY = "i2p.streaming.maxTotalConnsPerDay";
|
||||
protected static final String PROP_MAX_STREAMS = "i2p.streaming.maxConcurrentStreams";
|
||||
|
||||
public void setLimitMinute(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_CONNS_MIN, s.trim());
|
||||
}
|
||||
|
||||
public void setLimitHour(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_CONNS_HOUR, s.trim());
|
||||
}
|
||||
|
||||
public void setLimitDay(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_CONNS_DAY, s.trim());
|
||||
}
|
||||
|
||||
public void setTotalMinute(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_TOTAL_CONNS_MIN, s.trim());
|
||||
}
|
||||
|
||||
public void setTotalHour(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_TOTAL_CONNS_HOUR, s.trim());
|
||||
}
|
||||
|
||||
public void setTotalDay(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_TOTAL_CONNS_DAY, s.trim());
|
||||
}
|
||||
|
||||
public void setMaxStreams(String s) {
|
||||
if (s != null)
|
||||
_otherOptions.put(PROP_MAX_STREAMS, s.trim());
|
||||
}
|
||||
|
||||
/** params needed for hashcash and dest modification */
|
||||
public void setEffort(String val) {
|
||||
if (val != null) {
|
||||
@@ -831,17 +912,22 @@ public class IndexBean {
|
||||
Properties config = new Properties();
|
||||
updateConfigGeneric(config);
|
||||
|
||||
if ((isClient(_type) && !"streamrclient".equals(_type)) || "streamrserver".equals(_type)) {
|
||||
// streamrserver uses interface
|
||||
if (_reachableBy != null)
|
||||
config.setProperty("interface", _reachableBy);
|
||||
else
|
||||
config.setProperty("interface", "");
|
||||
} else {
|
||||
// streamrclient uses targetHost
|
||||
if (_targetHost != null)
|
||||
config.setProperty("targetHost", _targetHost);
|
||||
}
|
||||
|
||||
if (isClient(_type)) {
|
||||
// generic client stuff
|
||||
if (_port != null)
|
||||
config.setProperty("listenPort", _port);
|
||||
if (_reachableByOther != null)
|
||||
config.setProperty("interface", _reachableByOther);
|
||||
else if (_reachableBy != null)
|
||||
config.setProperty("interface", _reachableBy);
|
||||
else
|
||||
config.setProperty("interface", "");
|
||||
|
||||
config.setProperty("sharedClient", _sharedClient + "");
|
||||
for (String p : _booleanClientOpts)
|
||||
config.setProperty("option." + p, "" + _booleanOptions.contains(p));
|
||||
@@ -850,8 +936,6 @@ public class IndexBean {
|
||||
config.setProperty("option." + p, _otherOptions.get(p));
|
||||
} else {
|
||||
// generic server stuff
|
||||
if (_targetHost != null)
|
||||
config.setProperty("targetHost", _targetHost);
|
||||
if (_targetPort != null)
|
||||
config.setProperty("targetPort", _targetPort);
|
||||
for (String p : _booleanServerOpts)
|
||||
@@ -880,9 +964,7 @@ public class IndexBean {
|
||||
if ("httpbidirserver".equals(_type)) {
|
||||
if (_port != null)
|
||||
config.setProperty("listenPort", _port);
|
||||
if (_reachableByOther != null)
|
||||
config.setProperty("interface", _reachableByOther);
|
||||
else if (_reachableBy != null)
|
||||
if (_reachableBy != null)
|
||||
config.setProperty("interface", _reachableBy);
|
||||
else if (_targetHost != null)
|
||||
config.setProperty("interface", _targetHost);
|
||||
@@ -904,16 +986,20 @@ public class IndexBean {
|
||||
I2PTunnelHTTPClientBase.PROP_AUTH, I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH
|
||||
};
|
||||
private static final String _booleanServerOpts[] = {
|
||||
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", "i2cp.enableAccessList"
|
||||
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST
|
||||
};
|
||||
private static final String _otherClientOpts[] = {
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",
|
||||
"proxyUsername", "proxyPassword", "outproxyUsername", "outproxyPassword"
|
||||
"proxyUsername", "proxyPassword", "outproxyUsername", "outproxyPassword",
|
||||
I2PTunnelHTTPClient.PROP_JUMP_SERVERS
|
||||
};
|
||||
private static final String _otherServerOpts[] = {
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList"
|
||||
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList",
|
||||
PROP_MAX_CONNS_MIN, PROP_MAX_CONNS_HOUR, PROP_MAX_CONNS_DAY,
|
||||
PROP_MAX_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY,
|
||||
PROP_MAX_STREAMS
|
||||
};
|
||||
protected static final Set _noShowSet = new HashSet();
|
||||
protected static final Set _noShowSet = new HashSet(64);
|
||||
static {
|
||||
_noShowSet.addAll(Arrays.asList(_noShowOpts));
|
||||
_noShowSet.addAll(Arrays.asList(_booleanClientOpts));
|
||||
@@ -929,12 +1015,14 @@ public class IndexBean {
|
||||
config.setProperty("name", _name);
|
||||
if (_description != null)
|
||||
config.setProperty("description", _description);
|
||||
if (_i2cpHost != null)
|
||||
config.setProperty("i2cpHost", _i2cpHost);
|
||||
if ( (_i2cpPort != null) && (_i2cpPort.trim().length() > 0) ) {
|
||||
config.setProperty("i2cpPort", _i2cpPort);
|
||||
} else {
|
||||
config.setProperty("i2cpPort", "7654");
|
||||
if (!_context.isRouterContext()) {
|
||||
if (_i2cpHost != null)
|
||||
config.setProperty("i2cpHost", _i2cpHost);
|
||||
if ( (_i2cpPort != null) && (_i2cpPort.trim().length() > 0) ) {
|
||||
config.setProperty("i2cpPort", _i2cpPort);
|
||||
} else {
|
||||
config.setProperty("i2cpPort", "7654");
|
||||
}
|
||||
}
|
||||
if (_privKeyFile != null)
|
||||
config.setProperty("privKeyFile", _privKeyFile);
|
||||
@@ -1020,7 +1108,7 @@ public class IndexBean {
|
||||
}
|
||||
}
|
||||
|
||||
private String _(String key) {
|
||||
protected String _(String key) {
|
||||
return Messages._(key, _context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<label><%=intl._("Target")%>:</label>
|
||||
<% } else { %>
|
||||
<label><%=intl._("Access Point")%>:</label>
|
||||
<% } %>
|
||||
<% } /* streamrclient */ %>
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<label for="port" accesskey="P">
|
||||
@@ -95,46 +95,41 @@
|
||||
</label>
|
||||
<input type="text" size="6" maxlength="5" id="port" name="port" title="Access Port Number" value="<%=editBean.getClientPort(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<% String otherInterface = "";
|
||||
String clientInterface = editBean.getClientInterface(curTunnel);
|
||||
if ("streamrclient".equals(tunnelType)) {
|
||||
otherInterface = clientInterface;
|
||||
} else { %>
|
||||
<div id="reachField" class="rowItem">
|
||||
<label for="reachableBy" accesskey="r">
|
||||
<%=intl._("Reachable by")%>(<span class="accessKey">R</span>):
|
||||
</label>
|
||||
<select id="reachableBy" name="reachableBy" title="Valid IP for Client Access" class="selectbox">
|
||||
<% if (!("127.0.0.1".equals(clientInterface)) &&
|
||||
!("0.0.0.0".equals(clientInterface)) &&
|
||||
(clientInterface != null) &&
|
||||
(clientInterface.trim().length() > 0)) {
|
||||
otherInterface = clientInterface;
|
||||
}
|
||||
%><option value="127.0.0.1"<%=("127.0.0.1".equals(clientInterface) ? " selected=\"selected\"" : "")%>><%=intl._("Locally (127.0.0.1)")%></option>
|
||||
<option value="0.0.0.0"<%=("0.0.0.0".equals(clientInterface) ? " selected=\"selected\"" : "")%>><%=intl._("Everyone (0.0.0.0)")%></option>
|
||||
<option value="other"<%=(!("".equals(otherInterface)) ? " selected=\"selected\"" : "")%>><%=intl._("LAN Hosts (Please specify your LAN address)")%></option>
|
||||
</select>
|
||||
</div>
|
||||
<% } // streamrclient %>
|
||||
<div id="otherField" class="rowItem">
|
||||
<label for="reachableByOther" accesskey="O">
|
||||
<% if ("streamrclient".equals(tunnelType)) { %>
|
||||
Host:
|
||||
<% String vvv = otherInterface;
|
||||
if (vvv == null || "".equals(vvv.trim())) {
|
||||
<%
|
||||
if ("streamrclient".equals(tunnelType)) {
|
||||
out.write("Host:");
|
||||
String targetHost = editBean.getTargetHost(curTunnel);
|
||||
if (targetHost == null || "".equals(targetHost.trim())) {
|
||||
out.write(" <font color=\"red\">(");
|
||||
out.write(intl._("required"));
|
||||
out.write(")</font>");
|
||||
}
|
||||
%>
|
||||
<% } else { %>
|
||||
<%=intl._("Other")%>(<span class="accessKey">O</span>):
|
||||
<% } %>
|
||||
%>
|
||||
</label>
|
||||
<input type="text" size="20" id="reachableByOther" name="reachableByOther" title="Alternative IP for Client Access" value="<%=otherInterface%>" class="freetext" />
|
||||
</div>
|
||||
|
||||
<input type="text" size="20" id="targetHost" name="targetHost" title="Target Hostname or IP" value="<%=targetHost%>" class="freetext" />
|
||||
<% } else { %>
|
||||
<%=intl._("Reachable by")%>(<span class="accessKey">R</span>):
|
||||
</label>
|
||||
<select id="reachableBy" name="reachableBy" title="IP for Client Access" class="selectbox">
|
||||
<%
|
||||
String clientInterface = editBean.getClientInterface(curTunnel);
|
||||
for (String ifc : editBean.interfaceSet()) {
|
||||
out.write("<option value=\"");
|
||||
out.write(ifc);
|
||||
out.write('\"');
|
||||
if (ifc.equals(clientInterface))
|
||||
out.write(" selected=\"selected\"");
|
||||
out.write('>');
|
||||
out.write(ifc);
|
||||
out.write("</option>\n");
|
||||
}
|
||||
%>
|
||||
</select>
|
||||
<% } /* streamrclient */ %>
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
@@ -286,19 +281,19 @@
|
||||
<% } // !streamrclient %>
|
||||
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label><%=intl._("I2CP Options")%>:</label>
|
||||
<label><%=intl._("Router I2CP Address")%>:</label>
|
||||
</div>
|
||||
<div id="optionsHostField" class="rowItem">
|
||||
<label for="clientHost" accesskey="o">
|
||||
<%=intl._("Host")%>(<span class="accessKey">o</span>):
|
||||
</label>
|
||||
<input type="text" id="clientHost" name="clientHost" size="20" title="I2CP Hostname or IP" value="<%=editBean.getI2CPHost(curTunnel)%>" class="freetext" />
|
||||
<input type="text" id="clientHost" name="clientHost" size="20" title="I2CP Hostname or IP" value="<%=editBean.getI2CPHost(curTunnel)%>" class="freetext" <% if (editBean.isRouterContext()) { %> readonly="readonly" <% } %> />
|
||||
</div>
|
||||
<div id="optionsPortField" class="rowItem">
|
||||
<label for="clientPort" accesskey="r">
|
||||
<%=intl._("Port")%>(<span class="accessKey">r</span>):
|
||||
</label>
|
||||
<input type="text" id="port" name="clientport" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" />
|
||||
<input type="text" id="clientPort" name="clientport" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" <% if (editBean.isRouterContext()) { %> readonly="readonly" <% } %> />
|
||||
</div>
|
||||
|
||||
<% if (!"streamrclient".equals(tunnelType)) { // streamr client sends pings so it will never be idle %>
|
||||
@@ -465,6 +460,18 @@
|
||||
</div>
|
||||
<% } // httpclient || connect || socks || socksirc %>
|
||||
|
||||
<% if ("httpclient".equals(tunnelType)) { %>
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label><%=intl._("Jump URL List")%>:</label>
|
||||
</div>
|
||||
<div id="hostField" class="rowItem">
|
||||
<textarea rows="2" style="height: 8em;" cols="60" id="hostField" name="jumpList" title="List of helper URLs to offer when a host is not found in your addressbook" wrap="off"><%=editBean.getJumpList(curTunnel)%></textarea>
|
||||
</div>
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
<% } // httpclient %>
|
||||
|
||||
<div id="customOptionsField" class="rowItem">
|
||||
<label for="customOptions" accesskey="u">
|
||||
<%=intl._("Custom options")%>(<span class="accessKey">u</span>):
|
||||
|
||||
@@ -89,16 +89,14 @@
|
||||
<label><%=intl._("Target")%>:</label>
|
||||
<% } %>
|
||||
</div>
|
||||
<% if (!"streamrserver".equals(tunnelType)) { %>
|
||||
<div id="hostField" class="rowItem">
|
||||
<label for="targetHost" accesskey="H">
|
||||
<% if ("streamrserver".equals(tunnelType)) { %>
|
||||
<%=intl._("Reachable by")%>(<span class="accessKey">R</span>):
|
||||
<% } else { %>
|
||||
<%=intl._("Host")%>(<span class="accessKey">H</span>):
|
||||
<% } %>
|
||||
</label>
|
||||
<input type="text" size="20" id="targetHost" name="targetHost" title="Target Hostname or IP" value="<%=editBean.getTargetHost(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<% } /* !streamrserver */ %>
|
||||
<div id="portField" class="rowItem">
|
||||
<label for="targetPort" accesskey="P">
|
||||
<%=intl._("Port")%>(<span class="accessKey">P</span>):
|
||||
@@ -113,8 +111,7 @@
|
||||
<input type="text" size="6" maxlength="5" id="targetPort" name="targetPort" title="Target Port Number" value="<%=editBean.getTargetPort(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
|
||||
<% if ("httpbidirserver".equals(tunnelType)) {
|
||||
%>
|
||||
<% if ("httpbidirserver".equals(tunnelType)) { %>
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
@@ -134,32 +131,30 @@
|
||||
</label>
|
||||
<input type="text" size="6" maxlength="5" id="port" name="port" title="Access Port Number" value="<%=editBean.getClientPort(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<% String otherInterface = "";
|
||||
String clientInterface = editBean.getClientInterface(curTunnel);
|
||||
%>
|
||||
<% } /* httpbidirserver */ %>
|
||||
<% if ("httpbidirserver".equals(tunnelType) || "streamrserver".equals(tunnelType)) { %>
|
||||
<div id="reachField" class="rowItem">
|
||||
<label for="reachableBy" accesskey="r">
|
||||
<%=intl._("Reachable by")%>(<span class="accessKey">R</span>):
|
||||
</label>
|
||||
<select id="reachableBy" name="reachableBy" title="Valid IP for Client Access" class="selectbox">
|
||||
<% if (!("127.0.0.1".equals(clientInterface)) &&
|
||||
!("0.0.0.0".equals(clientInterface)) &&
|
||||
(clientInterface != null) &&
|
||||
(clientInterface.trim().length() > 0)) {
|
||||
otherInterface = clientInterface;
|
||||
}
|
||||
%><option value="127.0.0.1"<%=("127.0.0.1".equals(clientInterface) ? " selected=\"selected\"" : "")%>><%=intl._("Locally (127.0.0.1)")%></option>
|
||||
<option value="0.0.0.0"<%=("0.0.0.0".equals(clientInterface) ? " selected=\"selected\"" : "")%>><%=intl._("Everyone (0.0.0.0)")%></option>
|
||||
<option value="other"<%=(!("".equals(otherInterface)) ? " selected=\"selected\"" : "")%>><%=intl._("LAN Hosts (Please specify your LAN address)")%></option>
|
||||
<select id="reachableBy" name="reachableBy" title="IP for Client Access" class="selectbox">
|
||||
<%
|
||||
String clientInterface = editBean.getClientInterface(curTunnel);
|
||||
for (String ifc : editBean.interfaceSet()) {
|
||||
out.write("<option value=\"");
|
||||
out.write(ifc);
|
||||
out.write('\"');
|
||||
if (ifc.equals(clientInterface))
|
||||
out.write(" selected=\"selected\"");
|
||||
out.write('>');
|
||||
out.write(ifc);
|
||||
out.write("</option>\n");
|
||||
}
|
||||
%>
|
||||
</select>
|
||||
</div>
|
||||
<div id="otherField" class="rowItem">
|
||||
<label for="reachableByOther" accesskey="O">
|
||||
<%=intl._("Other")%>(<span class="accessKey">O</span>):
|
||||
</label>
|
||||
<input type="text" size="20" id="reachableByOther" name="reachableByOther" title="Alternative IP for Client Access" value="<%=otherInterface%>" class="freetext" />
|
||||
</div>
|
||||
<% } %>
|
||||
<% } /* httpbidirserver || streamrserver */ %>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
@@ -302,22 +297,22 @@
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
<% } // !streamrserver %>
|
||||
<% } /* !streamrserver */ %>
|
||||
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label><%=intl._("I2CP Options")%>:</label>
|
||||
<label><%=intl._("Router I2CP Address")%>:</label>
|
||||
</div>
|
||||
<div id="optionsHostField" class="rowItem">
|
||||
<label for="clientHost" accesskey="o">
|
||||
<%=intl._("Host")%>(<span class="accessKey">o</span>):
|
||||
</label>
|
||||
<input type="text" id="clientHost" name="clientHost" size="20" title="I2CP Hostname or IP" value="<%=editBean.getI2CPHost(curTunnel)%>" class="freetext" />
|
||||
<input type="text" id="clientHost" name="clientHost" size="20" title="I2CP Hostname or IP" value="<%=editBean.getI2CPHost(curTunnel)%>" class="freetext" <% if (editBean.isRouterContext()) { %> readonly="readonly" <% } %> />
|
||||
</div>
|
||||
<div id="optionsPortField" class="rowItem">
|
||||
<label for="clientPort" accesskey="r">
|
||||
<%=intl._("Port")%>(<span class="accessKey">r</span>):
|
||||
</label>
|
||||
<input type="text" id="clientPort" name="clientport" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" />
|
||||
<input type="text" id="clientPort" name="clientport" size="20" title="I2CP Port Number" value="<%=editBean.getI2CPPort(curTunnel)%>" class="freetext" <% if (editBean.isRouterContext()) { %> readonly="readonly" <% } %> />
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
@@ -333,7 +328,7 @@
|
||||
<label for="encrypt" accesskey="e">
|
||||
<%=intl._("Enable")%>:
|
||||
</label>
|
||||
<input value="1" type="checkbox" id="startOnLoad" name="encrypt" title="Encrypt LeaseSet"<%=(editBean.getEncrypt(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
<input value="1" type="checkbox" id="startOnLoad" name="encrypt" title="ONLY clients with the encryption key will be able to connect"<%=(editBean.getEncrypt(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<label for="encrypt" accesskey="e">
|
||||
@@ -359,19 +354,64 @@
|
||||
</label>
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<label for="access" accesskey="s">
|
||||
<%=intl._("Enable")%>:
|
||||
</label>
|
||||
<input value="1" type="checkbox" id="startOnLoad" name="access" title="Enable Access List"<%=(editBean.getAccess(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
<label><%=intl._("Disable")%></label>
|
||||
<input value="0" type="radio" id="startOnLoad" name="accessMode" title="Allow all clients"<%=(editBean.getAccessMode(curTunnel).equals("0") ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
<label><%=intl._("Whitelist")%></label>
|
||||
<input value="1" type="radio" id="startOnLoad" name="accessMode" title="Allow listed clients only"<%=(editBean.getAccessMode(curTunnel).equals("1") ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
<label><%=intl._("Blacklist")%></label>
|
||||
<input value="2" type="radio" id="startOnLoad" name="accessMode" title="Reject listed clients"<%=(editBean.getAccessMode(curTunnel).equals("2") ? " checked=\"checked\"" : "")%> class="tickbox" />
|
||||
</div>
|
||||
<div id="hostField" class="rowItem">
|
||||
<label for="accessList" accesskey="s">
|
||||
<%=intl._("Access List")%>:
|
||||
</label>
|
||||
<textarea rows="2" style="height: 4em;" cols="60" id="hostField" name="accessList" title="Access List" wrap="off"><%=editBean.getAccessList(curTunnel)%></textarea>
|
||||
<span class="comment"><%=intl._("(Restrict to these clients only)")%></span>
|
||||
<textarea rows="2" style="height: 8em;" cols="60" id="hostField" name="accessList" title="Access List" wrap="off"><%=editBean.getAccessList(curTunnel)%></textarea>
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<div class="rowItem">
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label><%=intl._("Inbound connection limits (0 to disable)")%><br><%=intl._("Per client")%>:</label>
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<label><%=intl._("Per minute")%>:</label>
|
||||
<input type="text" id="port" name="limitMinute" value="<%=editBean.getLimitMinute(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<label><%=intl._("Per hour")%>:</label>
|
||||
<input type="text" id="port" name="limitHour" value="<%=editBean.getLimitHour(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<label><%=intl._("Per day")%>:</label>
|
||||
<input type="text" id="port" name="limitDay" value="<%=editBean.getLimitDay(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label><%=intl._("Total")%>:</label>
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<input type="text" id="port" name="totalMinute" value="<%=editBean.getTotalMinute(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<input type="text" id="port" name="totalHour" value="<%=editBean.getTotalHour(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<input type="text" id="port" name="totalDay" value="<%=editBean.getTotalDay(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<div id="optionsField" class="rowItem">
|
||||
<label><%=intl._("Max concurrent connections (0 to disable)")%>:</label>
|
||||
</div>
|
||||
<div id="portField" class="rowItem">
|
||||
<input type="text" id="port" name="maxStreams" value="<%=editBean.getMaxStreams(curTunnel)%>" class="freetext" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="subdivider">
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
<label><%=intl._("Points at")%>:</label>
|
||||
<span class="text">
|
||||
<%
|
||||
if ("httpserver".equals(indexBean.getInternalType(curServer))) {
|
||||
if (indexBean.isServerTargetLinkValid(curServer)) {
|
||||
%>
|
||||
<a href="http://<%=indexBean.getServerTarget(curServer)%>/" title="Test HTTP server, bypassing I2P"><%=indexBean.getServerTarget(curServer)%></a>
|
||||
<%
|
||||
@@ -213,7 +213,18 @@
|
||||
</div>
|
||||
<div class="portField rowItem">
|
||||
<label><%=intl._("Port")%>:</label>
|
||||
<span class="text"><%=indexBean.getClientPort(curClient)%></span>
|
||||
<span class="text">
|
||||
<%
|
||||
String cPort= indexBean.getClientPort(curClient);
|
||||
if ("".equals(cPort)) {
|
||||
out.write("<font color=\"red\">");
|
||||
out.write(intl._("Port not set"));
|
||||
out.write("</font>");
|
||||
} else {
|
||||
out.write(cPort);
|
||||
}
|
||||
%>
|
||||
</span>
|
||||
</div>
|
||||
<div class="typeField rowItem">
|
||||
<label><%=intl._("Type")%>:</label>
|
||||
@@ -221,7 +232,19 @@
|
||||
</div>
|
||||
<div class="interfaceField rowItem">
|
||||
<label><%=intl._("Interface")%>:</label>
|
||||
<span class="text"><%=indexBean.getClientInterface(curClient)%></span>
|
||||
<span class="text">
|
||||
<%
|
||||
/* should only happen for streamr client */
|
||||
String cHost= indexBean.getClientInterface(curClient);
|
||||
if ("".equals(cHost)) {
|
||||
out.write("<font color=\"red\">");
|
||||
out.write(intl._("Host not set"));
|
||||
out.write("</font>");
|
||||
} else {
|
||||
out.write(cHost);
|
||||
}
|
||||
%>
|
||||
</span>
|
||||
</div>
|
||||
<div class="statusField rowItem">
|
||||
<label><%=intl._("Status")%>:</label>
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P i2ptunnel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-12-17 15:04+0000\n"
|
||||
"POT-Creation-Date: 2011-01-20 19:26+0000\n"
|
||||
"PO-Revision-Date: 2010-06-15 14:09+0100\n"
|
||||
"Last-Translator: duck <duck@mail.i2p>\n"
|
||||
"Language-Team: duck <duck@mail.i2p>, monkeybrains <monkeybrains@mail.i2p>\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Poedit-Language: Dutch\n"
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:475
|
||||
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:474
|
||||
#, java-format
|
||||
msgid ""
|
||||
"To visit the destination in your host database, click <a href=\"{0}\">here</"
|
||||
@@ -28,13 +28,18 @@ msgstr ""
|
||||
"\">hier</a>. Om de conflicterende adreshelper destination te bezoeken, klik "
|
||||
"<a href=\"{1}\">hier</a>."
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:932
|
||||
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:931
|
||||
msgid ""
|
||||
"Click a link below to look for an address helper by using a \"jump\" service:"
|
||||
msgstr ""
|
||||
"Klik op een onderstaande link om te zoeken naar een adreshelper via een "
|
||||
"\"jump\" service:"
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:326
|
||||
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:336
|
||||
msgid "internal"
|
||||
msgstr "intern"
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:170
|
||||
msgid ""
|
||||
"Invalid form submission, probably because you used the 'back' or 'reload' "
|
||||
@@ -109,6 +114,16 @@ msgstr "Streamr server"
|
||||
msgid "HTTP bidir"
|
||||
msgstr "HTTP bidir"
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:508
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:290
|
||||
msgid "Host not set"
|
||||
msgstr "Host niet opgegeven"
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:512
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:272
|
||||
msgid "Port not set"
|
||||
msgstr "Poort niet opgegeven"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:73
|
||||
msgid "I2P Tunnel Manager - Edit Client Tunnel"
|
||||
msgstr "I2P Tunnel Manager - Bewerk Client Tunnel"
|
||||
@@ -133,14 +148,14 @@ msgstr "Naam"
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:116
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:116
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:246
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:270
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:279
|
||||
msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:120
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:120
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:226
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:367
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:386
|
||||
msgid "Description"
|
||||
msgstr "Omschrijving"
|
||||
|
||||
@@ -151,66 +166,45 @@ msgstr "Doel"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:130
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:132
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:167
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:162
|
||||
msgid "Access Point"
|
||||
msgstr "Toegangspunt"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:137
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:179
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:207
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:157
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:172
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:228
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:150
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:192
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:153
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:167
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:213
|
||||
msgid "required"
|
||||
msgstr "vereist"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:150
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:142
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:183
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:159
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:178
|
||||
msgid "Reachable by"
|
||||
msgstr "Bereikbaar voor"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:162
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:195
|
||||
msgid "Locally (127.0.0.1)"
|
||||
msgstr "Lokaal (127.0.0.1)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:166
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:199
|
||||
msgid "Everyone (0.0.0.0)"
|
||||
msgstr "Iedereen (0.0.0.0)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:170
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:203
|
||||
msgid "LAN Hosts (Please specify your LAN address)"
|
||||
msgstr "LAN Hosts (Specificeer je LAN adres)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:186
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:205
|
||||
msgid "Other"
|
||||
msgstr "Anders"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:195
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:180
|
||||
msgid "Outproxies"
|
||||
msgstr "Uitgaande proxies"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:202
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:187
|
||||
msgid "Tunnel Destination"
|
||||
msgstr "Tunnel Destinations"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:214
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:199
|
||||
msgid "name or destination"
|
||||
msgstr "naam of destination"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:217
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:202
|
||||
msgid "b32 not recommended"
|
||||
msgstr "b32 niet aanbevolen"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:223
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:208
|
||||
msgid "Shared Client"
|
||||
msgstr "Gedeelde Client"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:227
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:212
|
||||
msgid ""
|
||||
"(Share tunnels with other clients and irc/httpclients? Change requires "
|
||||
"restart of client proxy)"
|
||||
@@ -218,22 +212,22 @@ msgstr ""
|
||||
"(Deel tunnels met andere clients en irc/httpclients? Wijziging vereist "
|
||||
"herstart van de client proxy)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:231
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:216
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:124
|
||||
msgid "Auto Start"
|
||||
msgstr "Auto Start"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:235
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:220
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:128
|
||||
msgid "(Check the Box for 'YES')"
|
||||
msgstr "(Markeer de Box voor 'JA')"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:237
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:258
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:222
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:243
|
||||
msgid "Advanced networking options"
|
||||
msgstr "Geavanceerde netwerk opties"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:239
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:224
|
||||
msgid ""
|
||||
"(NOTE: when this client proxy is configured to share tunnels, then these "
|
||||
"options are for all the shared proxy clients!)"
|
||||
@@ -241,93 +235,93 @@ msgstr ""
|
||||
"(OPMERKING: wanneer deze client proxy is geconfigureerd om tunnels te delen, "
|
||||
"dan zijn deze opties van toepassing voor alle gedeelde proxy clients!)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:241
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:260
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:226
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:245
|
||||
msgid "Tunnel Options"
|
||||
msgstr "Tunnel Opties"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:243
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:262
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:228
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:247
|
||||
msgid "Length"
|
||||
msgstr "Lengte"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:250
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:269
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:235
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:254
|
||||
msgid "0 hop tunnel (low anonymity, low latency)"
|
||||
msgstr "0 hop tunnel (lage anonimiteit, weinig vertraging)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:254
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:273
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:239
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:258
|
||||
msgid "1 hop tunnel (medium anonymity, medium latency)"
|
||||
msgstr "1 hop tunnel (gemiddelde anonimiteit, gemiddelde vertraging)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:258
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:277
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:243
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:262
|
||||
msgid "2 hop tunnel (high anonymity, high latency)"
|
||||
msgstr "2 hop tunnel (hoge anonimiteit, hoge vertraging)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:262
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:281
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:247
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:266
|
||||
msgid "3 hop tunnel (very high anonymity, poor performance)"
|
||||
msgstr "3 hop tunnel (zeer hoge anonimiteit, slechte prestatie)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:271
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:290
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:256
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:275
|
||||
msgid "hop tunnel (very poor performance)"
|
||||
msgstr "hop tunnel (zeer slechte prestatie)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:276
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:295
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:261
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:280
|
||||
msgid "Variance"
|
||||
msgstr "Variantie"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:283
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:302
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:268
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:287
|
||||
msgid "0 hop variance (no randomisation, consistant performance)"
|
||||
msgstr "0 hop variantie (geen randomisatie, consistente prestatie)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:287
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:306
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:272
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:291
|
||||
msgid ""
|
||||
"+ 0-1 hop variance (medium additive randomisation, subtractive performance)"
|
||||
msgstr ""
|
||||
"+ 0-1 hop variantie (gemiddeld toegevoegde randomisatie, minder prestatie)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:291
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:310
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:276
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:295
|
||||
msgid ""
|
||||
"+ 0-2 hop variance (high additive randomisation, subtractive performance)"
|
||||
msgstr "+ 0-2 hop variantie (hoge toegevoegde randomisatie, minder prestatie)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:295
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:314
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:280
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:299
|
||||
msgid "+/- 0-1 hop variance (standard randomisation, standard performance)"
|
||||
msgstr "+/- 0-1 hop variantie (standaard randomisatie, standaard prestatie)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:299
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:318
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:284
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:303
|
||||
msgid "+/- 0-2 hop variance (not recommended)"
|
||||
msgstr "+/- 0-2 hop variantie (niet aanbevolen)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:311
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:330
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:296
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:315
|
||||
msgid "hop variance"
|
||||
msgstr "hop variantie"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:316
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:335
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:301
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:320
|
||||
msgid "Count"
|
||||
msgstr "Aantal"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:323
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:342
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:308
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:327
|
||||
msgid "1 inbound, 1 outbound tunnel (low bandwidth usage, less reliability)"
|
||||
msgstr ""
|
||||
"1 inkomende, 1 uitgaande tunnel (laag bandbreedte gebruik, minder "
|
||||
"betrouwbaar)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:327
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:346
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:312
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:331
|
||||
msgid ""
|
||||
"2 inbound, 2 outbound tunnels (standard bandwidth usage, standard "
|
||||
"reliability)"
|
||||
@@ -335,185 +329,189 @@ msgstr ""
|
||||
"2 inkomende, 2 uitgaande tunnels (standaard bandbreedte gebruik, standaard "
|
||||
"betrouwbaarheid)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:331
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:350
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:316
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:335
|
||||
msgid ""
|
||||
"3 inbound, 3 outbound tunnels (higher bandwidth usage, higher reliability)"
|
||||
msgstr ""
|
||||
"3 inkomende, 3 uitgaande tunnels (hoge bandbreedte gebruik, hogere "
|
||||
"betrouwbaarheid)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:340
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:359
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:325
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:344
|
||||
msgid "tunnels"
|
||||
msgstr "tunnels"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:345
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:364
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:330
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:349
|
||||
msgid "Backup Count"
|
||||
msgstr "Backup Aantal"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:352
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:371
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:337
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:356
|
||||
msgid "0 backup tunnels (0 redundancy, no added resource usage)"
|
||||
msgstr "0 backup tunnels (0 redundantie, geen additionele bronnen gebruikt)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:356
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:375
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:341
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:360
|
||||
msgid "1 backup tunnel each direction (low redundancy, low resource usage)"
|
||||
msgstr ""
|
||||
"1 backup tunnel in beide richting (lage redundantie, lage aantal bronnen "
|
||||
"gebruikt)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:360
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:379
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:345
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:364
|
||||
msgid ""
|
||||
"2 backup tunnels each direction (medium redundancy, medium resource usage)"
|
||||
msgstr ""
|
||||
"2 backup tunnels in beide richting (gemiddelde redundantie, gemiddeld aantal "
|
||||
"bronnen gebruikt)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:364
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:383
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:349
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:368
|
||||
msgid "3 backup tunnels each direction (high redundancy, high resource usage)"
|
||||
msgstr ""
|
||||
"3 backup tunnels in beide richting (hoge redundantie, hoog aantal bronnen "
|
||||
"gebruikt)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:373
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:392
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:358
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:377
|
||||
msgid "backup tunnels"
|
||||
msgstr "backup tunnels"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:380
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:399
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:365
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:384
|
||||
msgid "Profile"
|
||||
msgstr "Profiel"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:387
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:406
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:372
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:391
|
||||
msgid "interactive connection"
|
||||
msgstr "interactieve connectie"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:391
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:410
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:376
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:395
|
||||
msgid "bulk connection (downloads/websites/BT)"
|
||||
msgstr "bulk connection (downloads/websites/BT)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:393
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:378
|
||||
msgid "Delay Connect"
|
||||
msgstr "Vertraagde Connectie"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:397
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:382
|
||||
msgid "for request/response connections"
|
||||
msgstr "voor request/response connecties"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:401
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:414
|
||||
msgid "I2CP Options"
|
||||
msgstr "I2CP Opties"
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:386
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:399
|
||||
msgid "Router I2CP Address"
|
||||
msgstr "Router I2CP Adres"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:403
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:146
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:416
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:388
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:142
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:401
|
||||
msgid "Host"
|
||||
msgstr "Host"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:407
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:152
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:420
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:396
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:148
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:409
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:244
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:266
|
||||
msgid "Port"
|
||||
msgstr "Poort"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:413
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:452
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:406
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:479
|
||||
msgid "Reduce tunnel quantity when idle"
|
||||
msgstr "Verminder tunnel aantal wanneer in rust"
|
||||
msgstr "Verminder tunnel aantal in ruststand"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:415
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:429
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:437
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:449
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:459
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:479
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:493
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:426
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:442
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:454
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:408
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:422
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:430
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:442
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:452
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:472
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:486
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:419
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:481
|
||||
msgid "Enable"
|
||||
msgstr "Ingeschakeld"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:419
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:458
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:412
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:485
|
||||
msgid "Reduced tunnel count"
|
||||
msgstr "Verminder tunnel aantal"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:423
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:443
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:462
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:416
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:436
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:489
|
||||
msgid "Idle minutes"
|
||||
msgstr "Rust minuten"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:427
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:420
|
||||
msgid "Close tunnels when idle"
|
||||
msgstr "Sluit tunnels wanneer in rust"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:433
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:426
|
||||
msgid "New Keys on Reopen"
|
||||
msgstr "Nieuwe Sleutels bij Heropenen"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:441
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:434
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:435
|
||||
msgid "Disable"
|
||||
msgstr "Uitgeschakeld"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:447
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:440
|
||||
msgid "Delay tunnel open until required"
|
||||
msgstr "Vertraag tunnel opening totdat het nodig is"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:457
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:450
|
||||
msgid "Persistent private key"
|
||||
msgstr "Persistente private sleutel"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:463
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:456
|
||||
msgid "File"
|
||||
msgstr "Bestand"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:467
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:235
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:460
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:220
|
||||
msgid "Local destination"
|
||||
msgstr "Lokale destination"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:471
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:464
|
||||
msgid "(if known)"
|
||||
msgstr "(indien bekend)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:477
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:470
|
||||
msgid "Local Authorization"
|
||||
msgstr "Lokale Autorisatie"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:483
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:497
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:476
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:490
|
||||
msgid "Username"
|
||||
msgstr "Gebruikersnaam"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:487
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:501
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:480
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:494
|
||||
msgid "Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:491
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:484
|
||||
msgid "Outproxy Authorization"
|
||||
msgstr "Uitgaande Proxy Autorisatie"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:507
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:498
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:502
|
||||
msgid "Jump URL List"
|
||||
msgstr "Spring URL Lijst"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:508
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:525
|
||||
msgid "Custom options"
|
||||
msgstr "Aangepaste opties"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:511
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:502
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:512
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:529
|
||||
msgid ""
|
||||
"NOTE: If tunnel is currently running, most changes will not take effect "
|
||||
"until tunnel is stopped and restarted."
|
||||
@@ -521,18 +519,18 @@ msgstr ""
|
||||
"OPMERKING: Indien de tunnel op dit moment draait, zullen de meeste "
|
||||
"wijzigingen pas effect hebben na het stoppen en herstarten van de tunnel."
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:513
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:504
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:514
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:531
|
||||
msgid "Cancel"
|
||||
msgstr "Annuleer"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:517
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:508
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:518
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:535
|
||||
msgid "Delete"
|
||||
msgstr "Verwijder"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:519
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:510
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:520
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:537
|
||||
msgid "Save"
|
||||
msgstr "Opslaan"
|
||||
|
||||
@@ -548,92 +546,124 @@ msgstr "Bewerk server instellingen"
|
||||
msgid "New server settings"
|
||||
msgstr "Nieuwe server instellingen"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:214
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:199
|
||||
msgid "Website name"
|
||||
msgstr "Website naam"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:218
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:203
|
||||
msgid "(leave blank for outproxies)"
|
||||
msgstr "(leeg laten voor uitgaande proxies)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:223
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:208
|
||||
msgid "Private key file"
|
||||
msgstr "Private sleutel bestand"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:245
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:230
|
||||
msgid "Add to local addressbook"
|
||||
msgstr "Toevoegen aan lokaal adresboek"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:252
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:237
|
||||
msgid "Hostname Signature"
|
||||
msgstr "Hostnaam Handtekening"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:424
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:417
|
||||
msgid "Encrypt Leaseset"
|
||||
msgstr "Versleutel Leaseset"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:430
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:423
|
||||
msgid "Encryption Key"
|
||||
msgstr "Encryptie Sleutel"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:434
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:427
|
||||
msgid "Generate New Key"
|
||||
msgstr "Genereer Nieuwe Sleutel"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:436
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:429
|
||||
msgid "Generate"
|
||||
msgstr "Genereer"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:438
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:496
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:431
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:523
|
||||
msgid "(Tunnel must be stopped first)"
|
||||
msgstr "(Tunnel moet eerst gestopt worden)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:440
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:433
|
||||
msgid "Restricted Access List"
|
||||
msgstr "Beperkte Toegangs Lijst"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:446
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:439
|
||||
msgid "Whitelist"
|
||||
msgstr "Wittelijst"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:443
|
||||
msgid "Blacklist"
|
||||
msgstr "Zwartelijst"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:447
|
||||
msgid "Access List"
|
||||
msgstr "Toegangs Lijst"
|
||||
msgstr "Toegangslijst"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:450
|
||||
msgid "(Restrict to these clients only)"
|
||||
msgstr "(Beperkt tot slechts deze clients)"
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:451
|
||||
msgid "Inbound connection limits (0 to disable)"
|
||||
msgstr "Inkomende connectie limieten (0 om uit te schakelen)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:466
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:453
|
||||
msgid "Per client"
|
||||
msgstr "Per client"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:455
|
||||
msgid "Per minute"
|
||||
msgstr "Per minuut"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:459
|
||||
msgid "Per hour"
|
||||
msgstr "Per uur"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:463
|
||||
msgid "Per day"
|
||||
msgstr "Per dag"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:467
|
||||
msgid "Total"
|
||||
msgstr "Totaal"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:475
|
||||
msgid "Max concurrent connections (0 to disable)"
|
||||
msgstr "Maximum gelijktijdige connecties (0 om uit te schakelen)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:493
|
||||
msgid "New Certificate type"
|
||||
msgstr "Nieuw Certificaat type"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:468
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:495
|
||||
msgid "None"
|
||||
msgstr "Geen"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:472
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:499
|
||||
msgid "Hashcash (effort)"
|
||||
msgstr "Hashcash (effort)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:478
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:505
|
||||
msgid "Hashcash Calc Time"
|
||||
msgstr "Hashcash Reken Tijd"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:480
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:507
|
||||
msgid "Estimate"
|
||||
msgstr "Inschatten"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:482
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:509
|
||||
msgid "Hidden"
|
||||
msgstr "Verborgen"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:486
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:513
|
||||
msgid "Signed (signed by)"
|
||||
msgstr "Ondertekend (ondertekend door)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:492
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:519
|
||||
msgid "Modify Certificate"
|
||||
msgstr "Wijzig Certificaat"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:494
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:521
|
||||
msgid "Modify"
|
||||
msgstr "Wijzig"
|
||||
|
||||
@@ -683,7 +713,7 @@ msgstr "Preview"
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:113
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:177
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:250
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:278
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:297
|
||||
msgid "Status"
|
||||
msgstr "Status"
|
||||
|
||||
@@ -696,30 +726,30 @@ msgid "No Preview"
|
||||
msgstr "Geen Preview"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:184
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:285
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:304
|
||||
msgid "Starting..."
|
||||
msgstr "Starten..."
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:191
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:205
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:292
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:306
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:320
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:311
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:325
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:339
|
||||
msgid "Stop"
|
||||
msgstr "Stop"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:198
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:313
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:332
|
||||
msgid "Running"
|
||||
msgstr "Draait"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:212
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:327
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:346
|
||||
msgid "Stopped"
|
||||
msgstr "Gestopt"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:219
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:334
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:353
|
||||
msgid "Start"
|
||||
msgstr "Start"
|
||||
|
||||
@@ -728,12 +758,12 @@ msgid "New server tunnel"
|
||||
msgstr "Nieuwe server tunnel"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:236
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:377
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:396
|
||||
msgid "Standard"
|
||||
msgstr "Standaard"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:238
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:379
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:398
|
||||
msgid "Create"
|
||||
msgstr "Creëer"
|
||||
|
||||
@@ -742,26 +772,26 @@ msgid "I2P Client Tunnels"
|
||||
msgstr "I2P Client Tunnels"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:248
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:274
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:283
|
||||
msgid "Interface"
|
||||
msgstr "Interface"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:299
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:318
|
||||
msgid "Standby"
|
||||
msgstr "Stand-by"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:344
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:363
|
||||
msgid "Outproxy"
|
||||
msgstr "Uitgaande proxy"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:348
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:367
|
||||
msgid "Destination"
|
||||
msgstr "Destination"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:362
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:381
|
||||
msgid "none"
|
||||
msgstr "geen"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:375
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:394
|
||||
msgid "New client tunnel"
|
||||
msgstr "Nieuwe client tunnel"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P i2ptunnel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-12-13 19:43+0000\n"
|
||||
"PO-Revision-Date: 2010-12-14 00:54+0500\n"
|
||||
"POT-Creation-Date: 2011-01-17 18:54+0000\n"
|
||||
"PO-Revision-Date: 2011-01-18 00:34+0500\n"
|
||||
"Last-Translator: Hidden Z <hiddenz@mail.i2p>\n"
|
||||
"Language-Team: foo <foo@bar>\n"
|
||||
"Language: \n"
|
||||
@@ -18,15 +18,20 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Poedit-Language: Russian\n"
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:475
|
||||
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:474
|
||||
#, java-format
|
||||
msgid "To visit the destination in your host database, click <a href=\"{0}\">here</a>. To visit the conflicting addresshelper destination, click <a href=\"{1}\">here</a>."
|
||||
msgstr "Для перехода по ссылке из локальной адресной книги, нажмите <a href=\"{0}\">здесь</a>. Для перехода по новой addresshelper-ссылке, нажмите <a href=\"{1}\">здесь</a>."
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:932
|
||||
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:931
|
||||
msgid "Click a link below to look for an address helper by using a \"jump\" service:"
|
||||
msgstr "Jump-сервисы, которые, возможно, знают нужную Вам addresshelper-ссылку:"
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:326
|
||||
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:336
|
||||
msgid "internal"
|
||||
msgstr "внутренний"
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:170
|
||||
msgid "Invalid form submission, probably because you used the 'back' or 'reload' button on your browser. Please resubmit."
|
||||
msgstr "Неправильно переданная форма, возможно вы использовали действие браузера \"назад\" или \"обновить\". Пожалуйста повторите попытку."
|
||||
@@ -97,6 +102,15 @@ msgstr "Streamr-сервер"
|
||||
msgid "HTTP bidir"
|
||||
msgstr "HTTP bidir (экспериментальный двунаправленный режим, инструкцию спрашивайте у sponge)"
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:508
|
||||
msgid "Host not set"
|
||||
msgstr "Хост не задан"
|
||||
|
||||
#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:512
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:272
|
||||
msgid "Port not set"
|
||||
msgstr "Порт не задан"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:73
|
||||
msgid "I2P Tunnel Manager - Edit Client Tunnel"
|
||||
msgstr "Менеджер Туннелей I2P — Редактирование Клиентского Туннеля"
|
||||
@@ -121,14 +135,14 @@ msgstr "Название"
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:116
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:116
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:246
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:270
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:279
|
||||
msgid "Type"
|
||||
msgstr "Тип"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:120
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:120
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:226
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:367
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:386
|
||||
msgid "Description"
|
||||
msgstr "Описание"
|
||||
|
||||
@@ -139,357 +153,340 @@ msgstr "Точка доступа"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:130
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:132
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:167
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:162
|
||||
msgid "Access Point"
|
||||
msgstr "Точка доступа"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:137
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:179
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:207
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:157
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:172
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:228
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:150
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:192
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:153
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:167
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:213
|
||||
msgid "required"
|
||||
msgstr "*"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:150
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:142
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:183
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:159
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:178
|
||||
msgid "Reachable by"
|
||||
msgstr "Кому будет доступно (Сетевой интерфейс)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:162
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:195
|
||||
msgid "Locally (127.0.0.1)"
|
||||
msgstr "Только в пределах этого компьютера (127.0.0.1)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:166
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:199
|
||||
msgid "Everyone (0.0.0.0)"
|
||||
msgstr "Всем (0.0.0.0)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:170
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:203
|
||||
msgid "LAN Hosts (Please specify your LAN address)"
|
||||
msgstr "Только из локальной сети (Введите свой LAN-адрес)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:186
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:205
|
||||
msgid "Other"
|
||||
msgstr "Адрес сетевого интерфейса"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:195
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:180
|
||||
msgid "Outproxies"
|
||||
msgstr "Список outproxy"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:202
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:187
|
||||
msgid "Tunnel Destination"
|
||||
msgstr "Адрес назначения туннеля"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:214
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:199
|
||||
msgid "name or destination"
|
||||
msgstr "имя или адрес"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:217
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:202
|
||||
msgid "b32 not recommended"
|
||||
msgstr "b32 не рекомендуется"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:223
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:208
|
||||
msgid "Shared Client"
|
||||
msgstr "Коллективный клиент"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:227
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:212
|
||||
msgid "(Share tunnels with other clients and irc/httpclients? Change requires restart of client proxy)"
|
||||
msgstr "(Использовать туннели коллективно/совместно с другими прокси-клиентами? Изменение настройки потребует перезапуска туннеля)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:231
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:216
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:124
|
||||
msgid "Auto Start"
|
||||
msgstr "Автозапуск"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:235
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:220
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:128
|
||||
msgid "(Check the Box for 'YES')"
|
||||
msgstr "(поставьте галочку для включения)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:237
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:258
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:222
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:243
|
||||
msgid "Advanced networking options"
|
||||
msgstr "Расширенные сетевые настройки"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:239
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:224
|
||||
msgid "(NOTE: when this client proxy is configured to share tunnels, then these options are for all the shared proxy clients!)"
|
||||
msgstr "(ПРИМЕЧАНИЕ: при коллективном использовании туннелей эти опции будут применяться ко всем коллективным прокси-клиентам!)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:241
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:260
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:226
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:245
|
||||
msgid "Tunnel Options"
|
||||
msgstr "Параметры туннеля"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:243
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:262
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:228
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:247
|
||||
msgid "Length"
|
||||
msgstr "Длина"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:250
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:269
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:235
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:254
|
||||
msgid "0 hop tunnel (low anonymity, low latency)"
|
||||
msgstr "0 хопов (низкая анонимность, малые задержки)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:254
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:273
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:239
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:258
|
||||
msgid "1 hop tunnel (medium anonymity, medium latency)"
|
||||
msgstr "1 хоп (умеренная анонимность, умеренные задержки)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:258
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:277
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:243
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:262
|
||||
msgid "2 hop tunnel (high anonymity, high latency)"
|
||||
msgstr "2 хопа (высокая анонимность, высокие задержки)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:262
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:281
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:247
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:266
|
||||
msgid "3 hop tunnel (very high anonymity, poor performance)"
|
||||
msgstr "3 хопа (очень высокая анонимность, низкая производительность)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:271
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:290
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:256
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:275
|
||||
msgid "hop tunnel (very poor performance)"
|
||||
msgstr "хопов (очень низкая производительность)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:276
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:295
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:261
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:280
|
||||
msgid "Variance"
|
||||
msgstr "Разброс"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:283
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:302
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:268
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:287
|
||||
msgid "0 hop variance (no randomisation, consistant performance)"
|
||||
msgstr "нулевой разброс (без рандомизации, фиксированная производительность)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:287
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:306
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:272
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:291
|
||||
msgid "+ 0-1 hop variance (medium additive randomisation, subtractive performance)"
|
||||
msgstr "+ 0-1 разброс (умеренно повышенная рандомизация, пониженная производительность)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:291
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:310
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:276
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:295
|
||||
msgid "+ 0-2 hop variance (high additive randomisation, subtractive performance)"
|
||||
msgstr "+ 0-2 разброс (сильно повышенная рандомизация, пониженная производительность)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:295
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:314
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:280
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:299
|
||||
msgid "+/- 0-1 hop variance (standard randomisation, standard performance)"
|
||||
msgstr "+/- 0-1 разброс (стандартная рандомизация, стандартная производительность)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:299
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:318
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:284
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:303
|
||||
msgid "+/- 0-2 hop variance (not recommended)"
|
||||
msgstr "+/- 0-2 разброс (не рекомендуется)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:311
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:330
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:296
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:315
|
||||
msgid "hop variance"
|
||||
msgstr "разброс"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:316
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:335
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:301
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:320
|
||||
msgid "Count"
|
||||
msgstr "Количество"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:323
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:342
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:308
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:327
|
||||
msgid "1 inbound, 1 outbound tunnel (low bandwidth usage, less reliability)"
|
||||
msgstr "1 входящий, 1 исходящий туннель (низкая пропускная способность, низкая надежность) "
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:327
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:346
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:312
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:331
|
||||
msgid "2 inbound, 2 outbound tunnels (standard bandwidth usage, standard reliability)"
|
||||
msgstr "2 входящих, 2 исходящих туннеля (стандартная пропускная способность, стандартная надежность)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:331
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:350
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:316
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:335
|
||||
msgid "3 inbound, 3 outbound tunnels (higher bandwidth usage, higher reliability)"
|
||||
msgstr "3 входящих, 3 исходящих туннеля (высокая пропускная способность, высокая надежность)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:340
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:359
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:325
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:344
|
||||
msgid "tunnels"
|
||||
msgstr "туннелей"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:345
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:364
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:330
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:349
|
||||
msgid "Backup Count"
|
||||
msgstr "Резервное количество"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:352
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:371
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:337
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:356
|
||||
msgid "0 backup tunnels (0 redundancy, no added resource usage)"
|
||||
msgstr "без резервных туннелей (отсутствие избыточности, отсутствие дополнительной нагрузки на систему)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:356
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:375
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:341
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:360
|
||||
msgid "1 backup tunnel each direction (low redundancy, low resource usage)"
|
||||
msgstr "1 резервный туннель в каждом направлении (низкая избыточность, низкая нагрузка на систему)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:360
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:379
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:345
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:364
|
||||
msgid "2 backup tunnels each direction (medium redundancy, medium resource usage)"
|
||||
msgstr "2 резервных туннеля в каждом направлении (умеренная избыточность, умеренная нагрузка на систему)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:364
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:383
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:349
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:368
|
||||
msgid "3 backup tunnels each direction (high redundancy, high resource usage)"
|
||||
msgstr "3 резервных туннеля в каждом направлении (высокая избыточность, высокая нагрузка на систему)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:373
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:392
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:358
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:377
|
||||
msgid "backup tunnels"
|
||||
msgstr "резервных туннелей"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:380
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:399
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:365
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:384
|
||||
msgid "Profile"
|
||||
msgstr "Режим"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:387
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:406
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:372
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:391
|
||||
msgid "interactive connection"
|
||||
msgstr "оптимизировать для малых задержек (irc)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:391
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:410
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:376
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:395
|
||||
msgid "bulk connection (downloads/websites/BT)"
|
||||
msgstr "оптимизировать для большого обьема (www/bittorrent)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:393
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:378
|
||||
msgid "Delay Connect"
|
||||
msgstr "Задержка соединения"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:397
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:382
|
||||
msgid "for request/response connections"
|
||||
msgstr "оптимизация для соединений, начинающихся с запроса клиента/ответа сервера"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:401
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:414
|
||||
msgid "I2CP Options"
|
||||
msgstr "Параметры I2CP"
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:386
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:399
|
||||
msgid "Router I2CP Address"
|
||||
msgstr "I2CP Адрес Роутера"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:403
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:146
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:416
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:388
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:142
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:401
|
||||
msgid "Host"
|
||||
msgstr "Адрес"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:407
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:152
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:420
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:396
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:148
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:409
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:244
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:266
|
||||
msgid "Port"
|
||||
msgstr "Порт"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:413
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:452
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:406
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:479
|
||||
msgid "Reduce tunnel quantity when idle"
|
||||
msgstr "Снижать количество туннелей при простое"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:415
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:429
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:437
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:449
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:459
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:479
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:493
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:426
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:442
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:454
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:408
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:422
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:430
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:442
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:452
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:472
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:486
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:419
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:481
|
||||
msgid "Enable"
|
||||
msgstr "Включить"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:419
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:458
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:412
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:485
|
||||
msgid "Reduced tunnel count"
|
||||
msgstr "Количество туннелей"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:423
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:443
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:462
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:416
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:436
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:489
|
||||
msgid "Idle minutes"
|
||||
msgstr "Минут простоя"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:427
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:420
|
||||
msgid "Close tunnels when idle"
|
||||
msgstr "Закрыть туннели при простое"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:433
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:426
|
||||
msgid "New Keys on Reopen"
|
||||
msgstr "Генерировать новый ключ при переоткрытии"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:441
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:434
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:435
|
||||
msgid "Disable"
|
||||
msgstr "Выключить"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:447
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:440
|
||||
msgid "Delay tunnel open until required"
|
||||
msgstr "Отложить запуск до первого запроса"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:457
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:450
|
||||
msgid "Persistent private key"
|
||||
msgstr "Постоянный секретный ключ"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:463
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:456
|
||||
msgid "File"
|
||||
msgstr "Файл"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:467
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:235
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:460
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:220
|
||||
msgid "Local destination"
|
||||
msgstr "Локальный адрес назначения"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:471
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:464
|
||||
msgid "(if known)"
|
||||
msgstr "(если известен)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:477
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:470
|
||||
msgid "Local Authorization"
|
||||
msgstr "Локальная авторизация"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:483
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:497
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:476
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:490
|
||||
msgid "Username"
|
||||
msgstr "Имя пользователя"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:487
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:501
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:480
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:494
|
||||
msgid "Password"
|
||||
msgstr "Пароль"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:491
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:484
|
||||
msgid "Outproxy Authorization"
|
||||
msgstr "Авторизация outproxy"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:507
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:498
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:502
|
||||
msgid "Jump URL List"
|
||||
msgstr "Список адресов jump-сервисов"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:508
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:525
|
||||
msgid "Custom options"
|
||||
msgstr "Дополнительные параметры"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:511
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:502
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:512
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:529
|
||||
msgid "NOTE: If tunnel is currently running, most changes will not take effect until tunnel is stopped and restarted."
|
||||
msgstr "ПРИМЕЧАНИЕ: для вступления в силу измененных настроек потребуется остановка и перезапуск туннеля"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:513
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:504
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:514
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:531
|
||||
msgid "Cancel"
|
||||
msgstr "Отмена"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:517
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:508
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:518
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:535
|
||||
msgid "Delete"
|
||||
msgstr "Удалить"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:519
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:510
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:520
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:537
|
||||
msgid "Save"
|
||||
msgstr "Сохранить"
|
||||
|
||||
@@ -505,92 +502,124 @@ msgstr "Редактирование настроек серверного ту
|
||||
msgid "New server settings"
|
||||
msgstr "Настройки нового серверного туннеля"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:214
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:199
|
||||
msgid "Website name"
|
||||
msgstr "Имя веб-сайта"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:218
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:203
|
||||
msgid "(leave blank for outproxies)"
|
||||
msgstr "(не заполнять для outproxy)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:223
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:208
|
||||
msgid "Private key file"
|
||||
msgstr "Файл секретного ключа"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:245
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:230
|
||||
msgid "Add to local addressbook"
|
||||
msgstr "Добавить в локальную адресную книгу"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:252
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:237
|
||||
msgid "Hostname Signature"
|
||||
msgstr "Подпись хоста"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:424
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:417
|
||||
msgid "Encrypt Leaseset"
|
||||
msgstr "Шифровать LeaseSet"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:430
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:423
|
||||
msgid "Encryption Key"
|
||||
msgstr "Ключ шифрования"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:434
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:427
|
||||
msgid "Generate New Key"
|
||||
msgstr "Сгенерировать новый ключ"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:436
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:429
|
||||
msgid "Generate"
|
||||
msgstr "Сгенерировать"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:438
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:496
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:431
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:523
|
||||
msgid "(Tunnel must be stopped first)"
|
||||
msgstr "(Туннель перед этим следует остановить)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:440
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:433
|
||||
msgid "Restricted Access List"
|
||||
msgstr "Ограниченный доступ"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:446
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:439
|
||||
msgid "Whitelist"
|
||||
msgstr "Белый список"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:443
|
||||
msgid "Blacklist"
|
||||
msgstr "Чёрный список"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:447
|
||||
msgid "Access List"
|
||||
msgstr "Список доступа"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:450
|
||||
msgid "(Restrict to these clients only)"
|
||||
msgstr "(Разрешить доступ только перечисленным клиентам)"
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:451
|
||||
msgid "Inbound connection limits (0 to disable)"
|
||||
msgstr "Ограничение входящих соединений (0 для отключения)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:466
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:453
|
||||
msgid "Per client"
|
||||
msgstr "На клиента"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:455
|
||||
msgid "Per minute"
|
||||
msgstr "В минуту"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:459
|
||||
msgid "Per hour"
|
||||
msgstr "В час"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:463
|
||||
msgid "Per day"
|
||||
msgstr "В сутки"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:467
|
||||
msgid "Total"
|
||||
msgstr "Всего"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:475
|
||||
msgid "Max concurrent connections (0 to disable)"
|
||||
msgstr "Максимум одновременных соединений (0 для отключения)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:493
|
||||
msgid "New Certificate type"
|
||||
msgstr "Создать новый сертификат. Тип"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:468
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:495
|
||||
msgid "None"
|
||||
msgstr "Без"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:472
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:499
|
||||
msgid "Hashcash (effort)"
|
||||
msgstr "Hashcash (экспериментальный)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:478
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:505
|
||||
msgid "Hashcash Calc Time"
|
||||
msgstr "Время генерации hashcash-сертификата"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:480
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:507
|
||||
msgid "Estimate"
|
||||
msgstr "Прогноз"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:482
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:509
|
||||
msgid "Hidden"
|
||||
msgstr "Скрытый"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:486
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:513
|
||||
msgid "Signed (signed by)"
|
||||
msgstr "Подписанный (указать кем подписан)"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:492
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:519
|
||||
msgid "Modify Certificate"
|
||||
msgstr "Изменить сертификат"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:494
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:521
|
||||
msgid "Modify"
|
||||
msgstr "Изменить"
|
||||
|
||||
@@ -640,7 +669,7 @@ msgstr "Предпросмотр"
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:113
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:177
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:250
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:278
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:297
|
||||
msgid "Status"
|
||||
msgstr "Состояние"
|
||||
|
||||
@@ -653,30 +682,30 @@ msgid "No Preview"
|
||||
msgstr "Предпросмотр недоступен"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:184
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:285
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:304
|
||||
msgid "Starting..."
|
||||
msgstr "Запускается..."
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:191
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:205
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:292
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:306
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:320
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:311
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:325
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:339
|
||||
msgid "Stop"
|
||||
msgstr "Остановить"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:198
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:313
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:332
|
||||
msgid "Running"
|
||||
msgstr "Запущен"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:212
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:327
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:346
|
||||
msgid "Stopped"
|
||||
msgstr "Остановлен"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:219
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:334
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:353
|
||||
msgid "Start"
|
||||
msgstr "Запустить"
|
||||
|
||||
@@ -685,12 +714,12 @@ msgid "New server tunnel"
|
||||
msgstr "Новый серверный туннель"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:236
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:377
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:396
|
||||
msgid "Standard"
|
||||
msgstr "Стандартный"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:238
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:379
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:398
|
||||
msgid "Create"
|
||||
msgstr "Создать"
|
||||
|
||||
@@ -699,30 +728,48 @@ msgid "I2P Client Tunnels"
|
||||
msgstr "Клиентские I2P туннели"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:248
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:274
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:283
|
||||
msgid "Interface"
|
||||
msgstr "Сетевой интерфейс"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:299
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:318
|
||||
msgid "Standby"
|
||||
msgstr "Режим ожидания"
|
||||
|
||||
# This term intentionally left in English
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:344
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:363
|
||||
msgid "Outproxy"
|
||||
msgstr "Outproxy"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:348
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:367
|
||||
msgid "Destination"
|
||||
msgstr "Адрес назначения"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:362
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:381
|
||||
msgid "none"
|
||||
msgstr "нет"
|
||||
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:375
|
||||
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:394
|
||||
msgid "New client tunnel"
|
||||
msgstr "Новый клиентский туннель"
|
||||
|
||||
#~ msgid "Locally (127.0.0.1)"
|
||||
#~ msgstr "Только в пределах этого компьютера (127.0.0.1)"
|
||||
|
||||
#~ msgid "Everyone (0.0.0.0)"
|
||||
#~ msgstr "Всем (0.0.0.0)"
|
||||
|
||||
#~ msgid "LAN Hosts (Please specify your LAN address)"
|
||||
#~ msgstr "Только из локальной сети (Введите свой LAN-адрес)"
|
||||
|
||||
#~ msgid "Other"
|
||||
#~ msgstr "Адрес сетевого интерфейса"
|
||||
|
||||
#~ msgid "I2CP Options"
|
||||
#~ msgstr "Параметры I2CP"
|
||||
|
||||
#~ msgid "(Restrict to these clients only)"
|
||||
#~ msgstr "(Разрешить доступ только перечисленным клиентам)"
|
||||
|
||||
#~ msgid "Unimplemented"
|
||||
#~ msgstr "не реализовано"
|
||||
|
||||
@@ -0,0 +1,809 @@
|
||||
// ========================================================================
|
||||
// $Id: ResourceHandler.java,v 1.66 2005/08/24 08:18:17 gregwilkins Exp $
|
||||
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========================================================================
|
||||
|
||||
package org.mortbay.http.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.mortbay.log.LogFactory;
|
||||
import org.mortbay.http.HttpException;
|
||||
import org.mortbay.http.HttpFields;
|
||||
import org.mortbay.http.HttpRequest;
|
||||
import org.mortbay.http.HttpResponse;
|
||||
import org.mortbay.http.InclusiveByteRange;
|
||||
import org.mortbay.http.MultiPartResponse;
|
||||
import org.mortbay.http.ResourceCache;
|
||||
import org.mortbay.util.CachedResource;
|
||||
import org.mortbay.util.IO;
|
||||
import org.mortbay.util.LogSupport;
|
||||
import org.mortbay.util.Resource;
|
||||
import org.mortbay.util.StringMap;
|
||||
import org.mortbay.util.TypeUtil;
|
||||
import org.mortbay.util.URI;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Handler to serve files and resources.
|
||||
* Serves files from a given resource URL base and implements
|
||||
* the GET, HEAD, DELETE, OPTIONS, PUT, MOVE methods and the
|
||||
* IfModifiedSince and IfUnmodifiedSince header fields.
|
||||
* A simple memory cache is also provided to reduce file I/O.
|
||||
* HTTP/1.1 ranges are supported.
|
||||
*
|
||||
* @version $Id: ResourceHandler.java,v 1.66 2005/08/24 08:18:17 gregwilkins Exp $
|
||||
* @author Nuno Pregui<75>a
|
||||
* @author Greg Wilkins
|
||||
*/
|
||||
public class ResourceHandler extends AbstractHttpHandler
|
||||
{
|
||||
private static Log log = LogFactory.getLog(ResourceHandler.class);
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
private boolean _acceptRanges=true;
|
||||
private boolean _redirectWelcomeFiles ;
|
||||
private String[] _methods=null;
|
||||
private String _allowed;
|
||||
private boolean _dirAllowed=true;
|
||||
private int _minGzipLength =-1;
|
||||
private StringMap _methodMap = new StringMap();
|
||||
{
|
||||
setAllowedMethods(new String[]
|
||||
{
|
||||
HttpRequest.__GET,
|
||||
HttpRequest.__POST,
|
||||
HttpRequest.__HEAD,
|
||||
HttpRequest.__OPTIONS,
|
||||
HttpRequest.__TRACE
|
||||
});
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
/** Construct a ResourceHandler.
|
||||
*/
|
||||
public ResourceHandler()
|
||||
{}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
public synchronized void start()
|
||||
throws Exception
|
||||
{
|
||||
super.start();
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------- */
|
||||
public void stop()
|
||||
throws InterruptedException
|
||||
{
|
||||
super.stop();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String[] getAllowedMethods()
|
||||
{
|
||||
return _methods;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setAllowedMethods(String[] methods)
|
||||
{
|
||||
StringBuffer b = new StringBuffer();
|
||||
_methods=methods;
|
||||
_methodMap.clear();
|
||||
for (int i=0;i<methods.length;i++)
|
||||
{
|
||||
_methodMap.put(methods[i],methods[i]);
|
||||
if (i>0)
|
||||
b.append(',');
|
||||
b.append(methods[i]);
|
||||
}
|
||||
_allowed=b.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isMethodAllowed(String method)
|
||||
{
|
||||
return _methodMap.get(method)!=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getAllowedString()
|
||||
{
|
||||
return _allowed;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isDirAllowed()
|
||||
{
|
||||
return _dirAllowed;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setDirAllowed(boolean dirAllowed)
|
||||
{
|
||||
_dirAllowed = dirAllowed;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isAcceptRanges()
|
||||
{
|
||||
return _acceptRanges;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return True if welcome files are redirected to. False if forward is used.
|
||||
*/
|
||||
public boolean getRedirectWelcome()
|
||||
{
|
||||
return _redirectWelcomeFiles;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param redirectWelcome True if welcome files are redirected to. False
|
||||
* if forward is used.
|
||||
*/
|
||||
public void setRedirectWelcome(boolean redirectWelcome)
|
||||
{
|
||||
_redirectWelcomeFiles = redirectWelcome;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set if the handler accepts range requests.
|
||||
* Default is false;
|
||||
* @param ar True if the handler should accept ranges
|
||||
*/
|
||||
public void setAcceptRanges(boolean ar)
|
||||
{
|
||||
_acceptRanges=ar;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get minimum content length for GZIP encoding.
|
||||
* @return Minimum length of content for gzip encoding or -1 if disabled.
|
||||
*/
|
||||
public int getMinGzipLength()
|
||||
{
|
||||
return _minGzipLength;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set minimum content length for GZIP encoding.
|
||||
* @param minGzipLength If set to a positive integer, then static content
|
||||
* larger than this will be served as gzip content encoded
|
||||
* if a matching resource is found ending with ".gz"
|
||||
*/
|
||||
public void setMinGzipLength(int minGzipLength)
|
||||
{
|
||||
_minGzipLength = minGzipLength;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** get Resource to serve.
|
||||
* Map a path to a resource. The default implementation calls
|
||||
* HttpContext.getResource but derived handers may provide
|
||||
* their own mapping.
|
||||
* @param pathInContext The path to find a resource for.
|
||||
* @return The resource to serve.
|
||||
*/
|
||||
protected Resource getResource(String pathInContext)
|
||||
throws IOException
|
||||
{
|
||||
return getHttpContext().getResource(pathInContext);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void handle(String pathInContext,
|
||||
String pathParams,
|
||||
HttpRequest request,
|
||||
HttpResponse response)
|
||||
throws HttpException, IOException
|
||||
{
|
||||
Resource resource = getResource(pathInContext);
|
||||
if (resource==null)
|
||||
return;
|
||||
|
||||
// Is the method allowed?
|
||||
if (!isMethodAllowed(request.getMethod()))
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("Method not allowed: "+request.getMethod());
|
||||
if (resource.exists())
|
||||
{
|
||||
setAllowHeader(response);
|
||||
response.sendError(HttpResponse.__405_Method_Not_Allowed);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the request
|
||||
try
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("PATH="+pathInContext+" RESOURCE="+resource);
|
||||
|
||||
// check filename
|
||||
String method=request.getMethod();
|
||||
if (method.equals(HttpRequest.__GET) ||
|
||||
method.equals(HttpRequest.__POST) ||
|
||||
method.equals(HttpRequest.__HEAD))
|
||||
handleGet(request, response, pathInContext, pathParams, resource);
|
||||
else if (method.equals(HttpRequest.__PUT))
|
||||
handlePut(request, response, pathInContext, resource);
|
||||
else if (method.equals(HttpRequest.__DELETE))
|
||||
handleDelete(request, response, pathInContext, resource);
|
||||
else if (method.equals(HttpRequest.__OPTIONS))
|
||||
handleOptions(response, pathInContext);
|
||||
else if (method.equals(HttpRequest.__MOVE))
|
||||
handleMove(request, response, pathInContext, resource);
|
||||
else if (method.equals(HttpRequest.__TRACE))
|
||||
handleTrace(request, response);
|
||||
else
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("Unknown action:"+method);
|
||||
// anything else...
|
||||
try{
|
||||
if (resource.exists())
|
||||
response.sendError(HttpResponse.__501_Not_Implemented);
|
||||
}
|
||||
catch(Exception e) {LogSupport.ignore(log,e);}
|
||||
}
|
||||
}
|
||||
catch(IllegalArgumentException e)
|
||||
{
|
||||
LogSupport.ignore(log,e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (resource!=null && !(resource instanceof CachedResource))
|
||||
resource.release();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
public void handleGet(HttpRequest request,
|
||||
HttpResponse response,
|
||||
String pathInContext,
|
||||
String pathParams,
|
||||
Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("Looking for "+resource);
|
||||
|
||||
if (resource!=null && resource.exists())
|
||||
{
|
||||
// check if directory
|
||||
if (resource.isDirectory())
|
||||
{
|
||||
if (!pathInContext.endsWith("/") && !pathInContext.equals("/"))
|
||||
{
|
||||
log.debug("Redirect to directory/");
|
||||
|
||||
String q=request.getQuery();
|
||||
|
||||
// Properly fix URI
|
||||
URI urifix = new URI(request.getRequestURL().toString());
|
||||
urifix.setPath(urifix.getPath());
|
||||
StringBuffer buf = new StringBuffer(urifix.toString());
|
||||
urifix = null;
|
||||
|
||||
if (q!=null&&q.length()!=0)
|
||||
{
|
||||
buf.append('?');
|
||||
buf.append(q);
|
||||
}
|
||||
response.setField(HttpFields.__Location, URI.addPaths(buf.toString(),"/"));
|
||||
response.setStatus(302);
|
||||
request.setHandled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// See if index file exists
|
||||
String welcome=getHttpContext().getWelcomeFile(resource);
|
||||
if (welcome!=null)
|
||||
{
|
||||
// Forward to the index
|
||||
String ipath=URI.addPaths(pathInContext,welcome);
|
||||
if (_redirectWelcomeFiles)
|
||||
{
|
||||
// Redirect to the index
|
||||
ipath=URI.addPaths(getHttpContext().getContextPath(),ipath);
|
||||
response.setContentLength(0);
|
||||
response.sendRedirect(ipath);
|
||||
}
|
||||
else
|
||||
{
|
||||
URI uri=request.getURI();
|
||||
uri.setPath(URI.addPaths(uri.getPath(),welcome));
|
||||
getHttpContext().handle(ipath,pathParams,request,response);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check modified dates
|
||||
if (!passConditionalHeaders(request,response,resource))
|
||||
return;
|
||||
// If we got here, no forward to index took place
|
||||
sendDirectory(request,response,resource,pathInContext.length()>1);
|
||||
}
|
||||
// check if it is a file
|
||||
else if (resource.exists())
|
||||
{
|
||||
// Check modified dates
|
||||
if (!passConditionalHeaders(request,response,resource))
|
||||
return;
|
||||
sendData(request,response,pathInContext,resource,true);
|
||||
}
|
||||
else
|
||||
// don't know what it is
|
||||
log.warn("Unknown file type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* Check modification date headers.
|
||||
*/
|
||||
private boolean passConditionalHeaders(HttpRequest request,
|
||||
HttpResponse response,
|
||||
Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if (!request.getMethod().equals(HttpRequest.__HEAD))
|
||||
{
|
||||
// If we have meta data for the file
|
||||
// Try a direct match for most common requests. Avoids
|
||||
// parsing the date.
|
||||
ResourceCache.ResourceMetaData metaData =
|
||||
(ResourceCache.ResourceMetaData)resource.getAssociate();
|
||||
if (metaData!=null)
|
||||
{
|
||||
String ifms=request.getField(HttpFields.__IfModifiedSince);
|
||||
String mdlm=metaData.getLastModified();
|
||||
if (ifms!=null && mdlm!=null && ifms.equals(mdlm))
|
||||
{
|
||||
response.setStatus(HttpResponse.__304_Not_Modified);
|
||||
request.setHandled(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
long date=0;
|
||||
// Parse the if[un]modified dates and compare to resource
|
||||
|
||||
if ((date=request.getDateField(HttpFields.__IfUnmodifiedSince))>0)
|
||||
{
|
||||
if (resource.lastModified()/1000 > date/1000)
|
||||
{
|
||||
response.sendError(HttpResponse.__412_Precondition_Failed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((date=request.getDateField(HttpFields.__IfModifiedSince))>0)
|
||||
{
|
||||
|
||||
if (resource.lastModified()/1000 <= date/1000)
|
||||
{
|
||||
response.setStatus(HttpResponse.__304_Not_Modified);
|
||||
request.setHandled(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void handlePut(HttpRequest request,
|
||||
HttpResponse response,
|
||||
String pathInContext,
|
||||
Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("PUT "+pathInContext+" in "+resource);
|
||||
|
||||
boolean exists=resource!=null && resource.exists();
|
||||
if (exists &&
|
||||
!passConditionalHeaders(request,response,resource))
|
||||
return;
|
||||
|
||||
if (pathInContext.endsWith("/"))
|
||||
{
|
||||
if (!exists)
|
||||
{
|
||||
if (!resource.getFile().mkdirs())
|
||||
response.sendError(HttpResponse.__403_Forbidden, "Directories could not be created");
|
||||
else
|
||||
{
|
||||
request.setHandled(true);
|
||||
response.setStatus(HttpResponse.__201_Created);
|
||||
response.commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
request.setHandled(true);
|
||||
response.setStatus(HttpResponse.__200_OK);
|
||||
response.commit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
int toRead = request.getContentLength();
|
||||
InputStream in = request.getInputStream();
|
||||
OutputStream out = resource.getOutputStream();
|
||||
if (toRead>=0)
|
||||
IO.copy(in,out,toRead);
|
||||
else
|
||||
IO.copy(in,out);
|
||||
out.close();
|
||||
request.setHandled(true);
|
||||
response.setStatus(exists
|
||||
?HttpResponse.__200_OK
|
||||
:HttpResponse.__201_Created);
|
||||
response.commit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,ex);
|
||||
response.sendError(HttpResponse.__403_Forbidden,
|
||||
ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void handleDelete(HttpRequest request,
|
||||
HttpResponse response,
|
||||
String pathInContext,
|
||||
Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("DELETE "+pathInContext+" from "+resource);
|
||||
|
||||
if (!resource.exists() ||
|
||||
!passConditionalHeaders(request,response,resource))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// delete the file
|
||||
if (resource.delete())
|
||||
response.setStatus(HttpResponse.__204_No_Content);
|
||||
else
|
||||
response.sendError(HttpResponse.__403_Forbidden);
|
||||
|
||||
// Send response
|
||||
request.setHandled(true);
|
||||
}
|
||||
catch (SecurityException sex)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,sex);
|
||||
response.sendError(HttpResponse.__403_Forbidden, sex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void handleMove(HttpRequest request,
|
||||
HttpResponse response,
|
||||
String pathInContext,
|
||||
Resource resource)
|
||||
throws IOException
|
||||
{
|
||||
if (!resource.exists() || !passConditionalHeaders(request,response,resource))
|
||||
return;
|
||||
|
||||
|
||||
String newPath = URI.canonicalPath(request.getField("New-uri"));
|
||||
if (newPath==null)
|
||||
{
|
||||
response.sendError(HttpResponse.__405_Method_Not_Allowed,
|
||||
"Bad new uri");
|
||||
return;
|
||||
}
|
||||
|
||||
String contextPath = getHttpContext().getContextPath();
|
||||
if (contextPath!=null && !newPath.startsWith(contextPath))
|
||||
{
|
||||
response.sendError(HttpResponse.__405_Method_Not_Allowed,
|
||||
"Not in context");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Find path
|
||||
try
|
||||
{
|
||||
// TODO - Check this
|
||||
String newInfo=newPath;
|
||||
if (contextPath!=null)
|
||||
newInfo=newInfo.substring(contextPath.length());
|
||||
Resource newFile = getHttpContext().getBaseResource().addPath(newInfo);
|
||||
|
||||
if(log.isDebugEnabled())log.debug("Moving "+resource+" to "+newFile);
|
||||
resource.renameTo(newFile);
|
||||
|
||||
response.setStatus(HttpResponse.__204_No_Content);
|
||||
request.setHandled(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,ex);
|
||||
setAllowHeader(response);
|
||||
response.sendError(HttpResponse.__405_Method_Not_Allowed,
|
||||
"Error:"+ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void handleOptions(HttpResponse response, String pathInContext)
|
||||
throws IOException
|
||||
{
|
||||
if ("*".equals(pathInContext))
|
||||
return;
|
||||
setAllowHeader(response);
|
||||
response.commit();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
void setAllowHeader(HttpResponse response)
|
||||
{
|
||||
response.setField(HttpFields.__Allow, getAllowedString());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void writeHeaders(HttpResponse response,Resource resource, long count)
|
||||
throws IOException
|
||||
{
|
||||
ResourceCache.ResourceMetaData metaData =
|
||||
(ResourceCache.ResourceMetaData)resource.getAssociate();
|
||||
|
||||
response.setContentType(metaData.getMimeType());
|
||||
if (count != -1)
|
||||
{
|
||||
if (count==resource.length())
|
||||
response.setField(HttpFields.__ContentLength,metaData.getLength());
|
||||
else
|
||||
response.setContentLength((int)count);
|
||||
}
|
||||
|
||||
response.setField(HttpFields.__LastModified,metaData.getLastModified());
|
||||
|
||||
if (_acceptRanges && response.getHttpRequest().getDotVersion()>0)
|
||||
response.setField(HttpFields.__AcceptRanges,"bytes");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void sendData(HttpRequest request,
|
||||
HttpResponse response,
|
||||
String pathInContext,
|
||||
Resource resource,
|
||||
boolean writeHeaders)
|
||||
throws IOException
|
||||
{
|
||||
long resLength=resource.length();
|
||||
|
||||
// see if there are any range headers
|
||||
Enumeration reqRanges =
|
||||
request.getDotVersion()>0
|
||||
?request.getFieldValues(HttpFields.__Range)
|
||||
:null;
|
||||
|
||||
if (!writeHeaders || reqRanges == null || !reqRanges.hasMoreElements())
|
||||
{
|
||||
// look for a gziped content.
|
||||
Resource data=resource;
|
||||
if (_minGzipLength>0)
|
||||
{
|
||||
String accept=request.getField(HttpFields.__AcceptEncoding);
|
||||
if (accept!=null && resLength>_minGzipLength &&
|
||||
!pathInContext.endsWith(".gz"))
|
||||
{
|
||||
Resource gz = getHttpContext().getResource(pathInContext+".gz");
|
||||
if (gz.exists() && accept.indexOf("gzip")>=0)
|
||||
{
|
||||
if(log.isDebugEnabled())log.debug("gzip="+gz);
|
||||
response.setField(HttpFields.__ContentEncoding,"gzip");
|
||||
data=gz;
|
||||
resLength=data.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
writeHeaders(response,resource,resLength);
|
||||
|
||||
request.setHandled(true);
|
||||
OutputStream out = response.getOutputStream();
|
||||
data.writeTo(out,0,resLength);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the satisfiable ranges
|
||||
List ranges =InclusiveByteRange.satisfiableRanges(reqRanges,resLength);
|
||||
if(log.isDebugEnabled())log.debug("ranges: " + reqRanges + " == " + ranges);
|
||||
|
||||
// if there are no satisfiable ranges, send 416 response
|
||||
if (ranges==null || ranges.size()==0)
|
||||
{
|
||||
log.debug("no satisfiable ranges");
|
||||
writeHeaders(response, resource, resLength);
|
||||
response.setStatus(HttpResponse.__416_Requested_Range_Not_Satisfiable);
|
||||
response.setReason((String)HttpResponse.__statusMsg
|
||||
.get(TypeUtil.newInteger(HttpResponse.__416_Requested_Range_Not_Satisfiable)));
|
||||
|
||||
response.setField(HttpFields.__ContentRange,
|
||||
InclusiveByteRange.to416HeaderRangeString(resLength));
|
||||
|
||||
OutputStream out = response.getOutputStream();
|
||||
resource.writeTo(out,0,resLength);
|
||||
request.setHandled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// if there is only a single valid range (must be satisfiable
|
||||
// since were here now), send that range with a 216 response
|
||||
if ( ranges.size()== 1)
|
||||
{
|
||||
InclusiveByteRange singleSatisfiableRange =
|
||||
(InclusiveByteRange)ranges.get(0);
|
||||
if(log.isDebugEnabled())log.debug("single satisfiable range: " + singleSatisfiableRange);
|
||||
long singleLength = singleSatisfiableRange.getSize(resLength);
|
||||
writeHeaders(response,resource,singleLength);
|
||||
response.setStatus(HttpResponse.__206_Partial_Content);
|
||||
response.setReason((String)HttpResponse.__statusMsg
|
||||
.get(TypeUtil.newInteger(HttpResponse.__206_Partial_Content)));
|
||||
response.setField(HttpFields.__ContentRange,
|
||||
singleSatisfiableRange.toHeaderRangeString(resLength));
|
||||
OutputStream out = response.getOutputStream();
|
||||
resource.writeTo(out,
|
||||
singleSatisfiableRange.getFirst(resLength),
|
||||
singleLength);
|
||||
request.setHandled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// multiple non-overlapping valid ranges cause a multipart
|
||||
// 216 response which does not require an overall
|
||||
// content-length header
|
||||
//
|
||||
ResourceCache.ResourceMetaData metaData =
|
||||
(ResourceCache.ResourceMetaData)resource.getAssociate();
|
||||
String encoding = metaData.getMimeType();
|
||||
MultiPartResponse multi = new MultiPartResponse(response);
|
||||
response.setStatus(HttpResponse.__206_Partial_Content);
|
||||
response.setReason((String)HttpResponse.__statusMsg
|
||||
.get(TypeUtil.newInteger(HttpResponse.__206_Partial_Content)));
|
||||
|
||||
// If the request has a "Request-Range" header then we need to
|
||||
// send an old style multipart/x-byteranges Content-Type. This
|
||||
// keeps Netscape and acrobat happy. This is what Apache does.
|
||||
String ctp;
|
||||
if (request.containsField(HttpFields.__RequestRange))
|
||||
ctp = "multipart/x-byteranges; boundary=";
|
||||
else
|
||||
ctp = "multipart/byteranges; boundary=";
|
||||
response.setContentType(ctp+multi.getBoundary());
|
||||
|
||||
InputStream in=(resource instanceof CachedResource)
|
||||
?null:resource.getInputStream();
|
||||
OutputStream out = response.getOutputStream();
|
||||
long pos=0;
|
||||
|
||||
for (int i=0;i<ranges.size();i++)
|
||||
{
|
||||
InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i);
|
||||
String header=HttpFields.__ContentRange+": "+
|
||||
ibr.toHeaderRangeString(resLength);
|
||||
if(log.isDebugEnabled())log.debug("multi range: "+encoding+" "+header);
|
||||
multi.startPart(encoding,new String[]{header});
|
||||
|
||||
long start=ibr.getFirst(resLength);
|
||||
long size=ibr.getSize(resLength);
|
||||
if (in!=null)
|
||||
{
|
||||
// Handle non cached resource
|
||||
if (start<pos)
|
||||
{
|
||||
in.close();
|
||||
in=resource.getInputStream();
|
||||
pos=0;
|
||||
}
|
||||
if (pos<start)
|
||||
{
|
||||
in.skip(start-pos);
|
||||
pos=start;
|
||||
}
|
||||
IO.copy(in,out,size);
|
||||
pos+=size;
|
||||
}
|
||||
else
|
||||
// Handle cached resource
|
||||
resource.writeTo(out,start,size);
|
||||
|
||||
}
|
||||
if (in!=null)
|
||||
in.close();
|
||||
multi.close();
|
||||
|
||||
request.setHandled(true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
void sendDirectory(HttpRequest request,
|
||||
HttpResponse response,
|
||||
Resource resource,
|
||||
boolean parent)
|
||||
throws IOException
|
||||
{
|
||||
if (!_dirAllowed)
|
||||
{
|
||||
response.sendError(HttpResponse.__403_Forbidden);
|
||||
return;
|
||||
}
|
||||
|
||||
request.setHandled(true);
|
||||
|
||||
if(log.isDebugEnabled())log.debug("sendDirectory: "+resource);
|
||||
byte[] data=null;
|
||||
if (resource instanceof CachedResource)
|
||||
data=((CachedResource)resource).getCachedData();
|
||||
|
||||
if (data==null)
|
||||
{
|
||||
String base = URI.addPaths(request.getPath(),"/");
|
||||
String dir = resource.getListHTML(URI.encodePath(base),parent);
|
||||
if (dir==null)
|
||||
{
|
||||
response.sendError(HttpResponse.__403_Forbidden,
|
||||
"No directory");
|
||||
return;
|
||||
}
|
||||
data=dir.getBytes("UTF8");
|
||||
if (resource instanceof CachedResource)
|
||||
((CachedResource)resource).setCachedData(data);
|
||||
}
|
||||
|
||||
response.setContentType("text/html; charset=UTF8");
|
||||
response.setContentLength(data.length);
|
||||
|
||||
if (request.getMethod().equals(HttpRequest.__HEAD))
|
||||
{
|
||||
response.commit();
|
||||
return;
|
||||
}
|
||||
|
||||
response.getOutputStream().write(data,0,data.length);
|
||||
response.commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
352
apps/jetty/java/src/org/mortbay/util/FileResource.java
Normal file
352
apps/jetty/java/src/org/mortbay/util/FileResource.java
Normal file
@@ -0,0 +1,352 @@
|
||||
// ========================================================================
|
||||
// $Id: FileResource.java,v 1.31 2006/01/04 13:55:31 gregwilkins Exp $
|
||||
// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========================================================================
|
||||
package org.mortbay.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.security.Permission;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.mortbay.log.LogFactory;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** File Resource.
|
||||
*
|
||||
* Handle resources of implied or explicit file type.
|
||||
* This class can check for aliasing in the filesystem (eg case
|
||||
* insensitivity). By default this is turned on if the platform does
|
||||
* not have the "/" path separator, or it can be controlled with the
|
||||
* "org.mortbay.util.FileResource.checkAliases" system parameter.
|
||||
*
|
||||
* If alias checking is turned on, then aliased resources are
|
||||
* treated as if they do not exist, nor can they be created.
|
||||
*
|
||||
* @version $Revision: 1.31 $
|
||||
* @author Greg Wilkins (gregw)
|
||||
*/
|
||||
public class FileResource extends URLResource
|
||||
{
|
||||
private static Log log = LogFactory.getLog(Credential.class);
|
||||
private static boolean __checkAliases;
|
||||
static
|
||||
{
|
||||
__checkAliases=
|
||||
"true".equalsIgnoreCase
|
||||
(System.getProperty("org.mortbay.util.FileResource.checkAliases","true"));
|
||||
|
||||
if (__checkAliases)
|
||||
log.info("Checking Resource aliases");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private File _file;
|
||||
private transient URL _alias=null;
|
||||
private transient boolean _aliasChecked=false;
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/** setCheckAliases.
|
||||
* @param checkAliases True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
|
||||
*/
|
||||
public static void setCheckAliases(boolean checkAliases)
|
||||
{
|
||||
__checkAliases=checkAliases;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/** getCheckAliases.
|
||||
* @return True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found.
|
||||
*/
|
||||
public static boolean getCheckAliases()
|
||||
{
|
||||
return __checkAliases;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
FileResource(URL url)
|
||||
throws IOException, URISyntaxException
|
||||
{
|
||||
super(url,null);
|
||||
|
||||
try
|
||||
{
|
||||
// Try standard API to convert URL to file.
|
||||
_file =new File(new URI(url.toString()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogSupport.ignore(log,e);
|
||||
try
|
||||
{
|
||||
// Assume that File.toURL produced unencoded chars. So try
|
||||
// encoding them.
|
||||
String urls=
|
||||
"file:"+org.mortbay.util.URI.encodePath(url.toString().substring(5));
|
||||
_file =new File(new URI(urls));
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
LogSupport.ignore(log,e2);
|
||||
|
||||
// Still can't get the file. Doh! try good old hack!
|
||||
checkConnection();
|
||||
Permission perm = _connection.getPermission();
|
||||
_file = new File(perm==null?url.getFile():perm.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (_file.isDirectory() && !_urlString.endsWith("/"))
|
||||
_urlString=_urlString+"/";
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
FileResource(URL url, URLConnection connection, File file)
|
||||
{
|
||||
super(url,connection);
|
||||
_file=file;
|
||||
if (_file.isDirectory() && !_urlString.endsWith("/"))
|
||||
_urlString=_urlString+"/";
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
public Resource addPath(String path)
|
||||
throws IOException,MalformedURLException
|
||||
{
|
||||
FileResource r=null;
|
||||
|
||||
if (!isDirectory())
|
||||
{
|
||||
r=(FileResource)super.addPath(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = org.mortbay.util.URI.canonicalPath(path);
|
||||
|
||||
// treat all paths being added as relative
|
||||
String rel=path;
|
||||
if (path.startsWith("/"))
|
||||
rel = path.substring(1);
|
||||
|
||||
File newFile = new File(_file,rel.replace('/', File.separatorChar));
|
||||
r=new FileResource(newFile.toURI().toURL(),null,newFile);
|
||||
}
|
||||
|
||||
String encoded=org.mortbay.util.URI.encodePath(path);
|
||||
int expected=r._urlString.length()-encoded.length();
|
||||
int index = r._urlString.lastIndexOf(encoded, expected);
|
||||
|
||||
if (expected!=index && ((expected-1)!=index || path.endsWith("/") || !r.isDirectory()))
|
||||
{
|
||||
r._alias=r._url;
|
||||
r._aliasChecked=true;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public URL getAlias()
|
||||
{
|
||||
if (__checkAliases) {
|
||||
if (!_aliasChecked)
|
||||
{
|
||||
try
|
||||
{
|
||||
String abs=_file.getAbsolutePath();
|
||||
String can=_file.getCanonicalPath();
|
||||
|
||||
if (abs.length()!=can.length() || !abs.equals(can))
|
||||
_alias=new File(can).toURI().toURL();
|
||||
|
||||
_aliasChecked=true;
|
||||
|
||||
if (_alias!=null && log.isDebugEnabled())
|
||||
{
|
||||
log.debug("ALIAS abs="+abs);
|
||||
log.debug("ALIAS can="+can);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,e);
|
||||
return getURL();
|
||||
}
|
||||
}
|
||||
} else return null;
|
||||
return _alias;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
/**
|
||||
* Returns true if the resource exists.
|
||||
*/
|
||||
public boolean exists()
|
||||
{
|
||||
return _file.exists();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
/**
|
||||
* Returns the last modified time
|
||||
*/
|
||||
public long lastModified()
|
||||
{
|
||||
return _file.lastModified();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
/**
|
||||
* Returns true if the respresenetd resource is a container/directory.
|
||||
*/
|
||||
public boolean isDirectory()
|
||||
{
|
||||
return _file.isDirectory();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Return the length of the resource
|
||||
*/
|
||||
public long length()
|
||||
{
|
||||
return _file.length();
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Returns the name of the resource
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return _file.getAbsolutePath();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns an File representing the given resource or NULL if this
|
||||
* is not possible.
|
||||
*/
|
||||
public File getFile()
|
||||
{
|
||||
return _file;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Returns an input stream to the resource
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException
|
||||
{
|
||||
return new FileInputStream(_file);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Returns an output stream to the resource
|
||||
*/
|
||||
public OutputStream getOutputStream()
|
||||
throws java.io.IOException, SecurityException
|
||||
{
|
||||
return new FileOutputStream(_file);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Deletes the given resource
|
||||
*/
|
||||
public boolean delete()
|
||||
throws SecurityException
|
||||
{
|
||||
return _file.delete();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Rename the given resource
|
||||
*/
|
||||
public boolean renameTo( Resource dest)
|
||||
throws SecurityException
|
||||
{
|
||||
if( dest instanceof FileResource)
|
||||
return _file.renameTo( ((FileResource)dest)._file);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/**
|
||||
* Returns a list of resources contained in the given resource
|
||||
*/
|
||||
public String[] list()
|
||||
{
|
||||
String[] list =_file.list();
|
||||
if (list==null)
|
||||
return null;
|
||||
for (int i=list.length;i-->0;)
|
||||
{
|
||||
if (new File(_file,list[i]).isDirectory() &&
|
||||
!list[i].endsWith("/"))
|
||||
list[i]+="/";
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Encode according to this resource type.
|
||||
* File URIs are encoded.
|
||||
* @param uri URI to encode.
|
||||
* @return The uri unchanged.
|
||||
*/
|
||||
public String encode(String uri)
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param o
|
||||
* @return
|
||||
*/
|
||||
public boolean equals( Object o)
|
||||
{
|
||||
if (this == o)
|
||||
return true;
|
||||
|
||||
if (null == o || ! (o instanceof FileResource))
|
||||
return false;
|
||||
|
||||
FileResource f=(FileResource)o;
|
||||
return f._file == _file || (null != _file && _file.equals(f._file));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return the hashcode.
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return null == _file ? super.hashCode() : _file.hashCode();
|
||||
}
|
||||
}
|
||||
1010
apps/jetty/java/src/org/mortbay/util/URI.java
Normal file
1010
apps/jetty/java/src/org/mortbay/util/URI.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -19,9 +19,10 @@ public interface I2PServerSocket {
|
||||
/**
|
||||
* Waits for the next socket connecting. If a remote user tried to make a
|
||||
* connection and the local application wasn't .accept()ing new connections,
|
||||
* they should get refused (if .accept() doesnt occur in some small period)
|
||||
* they should get refused (if .accept() doesnt occur in some small period).
|
||||
* Warning - unlike regular ServerSocket, may return null.
|
||||
*
|
||||
* @return a connected I2PSocket
|
||||
* @return a connected I2PSocket OR NULL
|
||||
*
|
||||
* @throws I2PException if there is a problem with reading a new socket
|
||||
* from the data available (aka the I2PSession closed, etc)
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.router.client.ClientManagerFacadeImpl;
|
||||
import net.i2p.router.startup.ClientAppConfig;
|
||||
import net.i2p.router.startup.LoadClientAppsJob;
|
||||
|
||||
@@ -35,6 +36,10 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
saveClientChanges();
|
||||
return;
|
||||
}
|
||||
if (_action.equals(_("Save Interface Configuration"))) {
|
||||
saveInterfaceChanges();
|
||||
return;
|
||||
}
|
||||
if (_action.equals(_("Save WebApp Configuration"))) {
|
||||
saveWebAppChanges();
|
||||
return;
|
||||
@@ -193,7 +198,7 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
String[] arr = (String[]) _settings.get(key);
|
||||
if (arr == null)
|
||||
return null;
|
||||
return arr[0];
|
||||
return arr[0].trim();
|
||||
}
|
||||
|
||||
private void startClient(int i) {
|
||||
@@ -337,4 +342,37 @@ public class ConfigClientsHandler extends FormHandler {
|
||||
_log.error("Error starting plugin " + app, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle interface form
|
||||
* @since 0.8.3
|
||||
*/
|
||||
private void saveInterfaceChanges() {
|
||||
String port = getJettyString("port");
|
||||
if (port != null)
|
||||
_context.router().setConfigSetting(ClientManagerFacadeImpl.PROP_CLIENT_PORT, port);
|
||||
String intfc = getJettyString("interface");
|
||||
if (intfc != null)
|
||||
_context.router().setConfigSetting(ClientManagerFacadeImpl.PROP_CLIENT_HOST, intfc);
|
||||
String user = getJettyString("user");
|
||||
if (user != null)
|
||||
_context.router().setConfigSetting(ConfigClientsHelper.PROP_USER, user);
|
||||
String pw = getJettyString("pw");
|
||||
if (pw != null)
|
||||
_context.router().setConfigSetting(ConfigClientsHelper.PROP_PW, pw);
|
||||
String mode = getJettyString("mode");
|
||||
boolean disabled = "0".equals(mode);
|
||||
boolean ssl = "2".equals(mode);
|
||||
_context.router().setConfigSetting(ConfigClientsHelper.PROP_DISABLE_EXTERNAL,
|
||||
Boolean.toString(disabled));
|
||||
_context.router().setConfigSetting(ConfigClientsHelper.PROP_ENABLE_SSL,
|
||||
Boolean.toString(ssl));
|
||||
_context.router().setConfigSetting(ConfigClientsHelper.PROP_AUTH,
|
||||
Boolean.toString((_settings.get("auth") != null)));
|
||||
boolean all = "0.0.0.0".equals(intfc) || "0:0:0:0:0:0:0:0".equals(intfc) ||
|
||||
"::".equals(intfc);
|
||||
_context.router().setConfigSetting(ConfigClientsHelper.BIND_ALL_INTERFACES, Boolean.toString(all));
|
||||
_context.router().saveConfig();
|
||||
addFormNotice(_("Interface configuration saved successfully - restart required to take effect."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -8,13 +9,76 @@ import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import net.i2p.router.client.ClientManagerFacadeImpl;
|
||||
import net.i2p.router.startup.ClientAppConfig;
|
||||
import net.i2p.util.Addresses;
|
||||
|
||||
public class ConfigClientsHelper extends HelperBase {
|
||||
private String _edit;
|
||||
|
||||
/** from ClientListenerRunner */
|
||||
public static final String BIND_ALL_INTERFACES = "i2cp.tcp.bindAllInterfaces";
|
||||
/** from ClientManager */
|
||||
public static final String PROP_DISABLE_EXTERNAL = "i2cp.disableInterface";
|
||||
public static final String PROP_ENABLE_SSL = "i2cp.SSL";
|
||||
/** from ClientMessageEventListener */
|
||||
public static final String PROP_AUTH = "i2cp.auth";
|
||||
public static final String PROP_USER = "i2cp.username";
|
||||
public static final String PROP_PW = "i2cp.password";
|
||||
|
||||
public ConfigClientsHelper() {}
|
||||
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public String getPort() {
|
||||
return _context.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_PORT,
|
||||
Integer.toString(ClientManagerFacadeImpl.DEFAULT_PORT));
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public String getUser() {
|
||||
return _context.getProperty(PROP_USER, "");
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public String getPw() {
|
||||
return _context.getProperty(PROP_PW, "");
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public String i2cpModeChecked(int mode) {
|
||||
boolean disabled = _context.getBooleanProperty(PROP_DISABLE_EXTERNAL);
|
||||
boolean ssl = _context.getBooleanProperty(PROP_ENABLE_SSL);
|
||||
if ((mode == 0 && disabled) ||
|
||||
(mode == 1 && (!disabled) && (!ssl)) ||
|
||||
(mode == 2 && (!disabled) && ssl))
|
||||
return "checked=\"true\"";
|
||||
return "";
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public String getAuth() {
|
||||
boolean enabled = _context.getBooleanProperty(PROP_AUTH);
|
||||
if (enabled)
|
||||
return "checked=\"true\"";
|
||||
return "";
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public String[] intfcAddresses() {
|
||||
ArrayList<String> al = new ArrayList(Addresses.getAllAddresses());
|
||||
return al.toArray(new String[al.size()]);
|
||||
}
|
||||
|
||||
/** @since 0.8.3 */
|
||||
public boolean isIFSelected(String addr) {
|
||||
boolean bindAll = _context.getBooleanProperty(BIND_ALL_INTERFACES);
|
||||
if (bindAll && addr.equals("0.0.0.0") || addr.equals("::"))
|
||||
return true;
|
||||
String host = _context.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_HOST,
|
||||
ClientManagerFacadeImpl.DEFAULT_HOST);
|
||||
return (host.equals(addr));
|
||||
}
|
||||
|
||||
public void setEdit(String edit) {
|
||||
if (edit == null)
|
||||
return;
|
||||
@@ -41,7 +105,9 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
for (int cur = 0; cur < clients.size(); cur++) {
|
||||
ClientAppConfig ca = clients.get(cur);
|
||||
renderForm(buf, ""+cur, ca.clientName, false, !ca.disabled,
|
||||
"webConsole".equals(ca.clientName) || "Web console".equals(ca.clientName),
|
||||
// dangerous, but allow editing the console args too
|
||||
//"webConsole".equals(ca.clientName) || "Web console".equals(ca.clientName),
|
||||
false,
|
||||
ca.className + ((ca.args != null) ? " " + ca.args : ""), (""+cur).equals(_edit),
|
||||
true, false, false, true, ca.disabled);
|
||||
}
|
||||
@@ -92,9 +158,9 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
continue;
|
||||
StringBuilder desc = new StringBuilder(256);
|
||||
desc.append("<table border=\"0\">")
|
||||
.append("<tr><td><b>").append(_("Version")).append("<td>").append(stripHTML(appProps, "version"))
|
||||
.append("<tr><td><b>").append(_("Version")).append("</b></td><td>").append(stripHTML(appProps, "version"))
|
||||
.append("<tr><td><b>")
|
||||
.append(_("Signed by")).append("<td>");
|
||||
.append(_("Signed by")).append("</b></td><td>");
|
||||
String s = stripHTML(appProps, "signer");
|
||||
if (s != null) {
|
||||
if (s.indexOf("@") > 0)
|
||||
@@ -111,13 +177,13 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
if (ms > 0) {
|
||||
String date = (new SimpleDateFormat("yyyy-MM-dd HH:mm")).format(new Date(ms));
|
||||
desc.append("<tr><td><b>")
|
||||
.append(_("Date")).append("<td>").append(date);
|
||||
.append(_("Date")).append("</b></td><td>").append(date);
|
||||
}
|
||||
}
|
||||
s = stripHTML(appProps, "author");
|
||||
if (s != null) {
|
||||
desc.append("<tr><td><b>")
|
||||
.append(_("Author")).append("<td>");
|
||||
.append(_("Author")).append("</b></td><td>");
|
||||
if (s.indexOf("@") > 0)
|
||||
desc.append("<a href=\"mailto:").append(s).append("\">").append(s).append("</a>");
|
||||
else
|
||||
@@ -128,12 +194,12 @@ public class ConfigClientsHelper extends HelperBase {
|
||||
s = stripHTML(appProps, "description");
|
||||
if (s != null) {
|
||||
desc.append("<tr><td><b>")
|
||||
.append(_("Description")).append("<td>").append(s);
|
||||
.append(_("Description")).append("</b></td><td>").append(s);
|
||||
}
|
||||
s = stripHTML(appProps, "license");
|
||||
if (s != null) {
|
||||
desc.append("<tr><td><b>")
|
||||
.append(_("License")).append("<td>").append(s);
|
||||
.append(_("License")).append("</b></td><td>").append(s);
|
||||
}
|
||||
s = stripHTML(appProps, "websiteURL");
|
||||
if (s != null) {
|
||||
|
||||
@@ -38,7 +38,7 @@ public class ConfigLoggingHelper extends HelperBase {
|
||||
sortedLogs.add(prefix);
|
||||
}
|
||||
|
||||
buf.append("<textarea name=\"levels\" rows=\"4\" cols=\"60\" wrap=\"off\">");
|
||||
buf.append("<textarea name=\"levels\" rows=\"4\" cols=\"60\" wrap=\"off\" spellcheck=\"false\">");
|
||||
for (Iterator iter = sortedLogs.iterator(); iter.hasNext(); ) {
|
||||
String prefix = (String)iter.next();
|
||||
String level = limits.getProperty(prefix);
|
||||
|
||||
@@ -12,12 +12,12 @@ public class ConfigNavHelper extends HelperBase {
|
||||
private static final String pages[] =
|
||||
{"", "ui", "service", "update", "tunnels",
|
||||
"clients", "peer", "keyring", "logging", "stats",
|
||||
"advanced" };
|
||||
"reseed", "advanced" };
|
||||
|
||||
private static final String titles[] =
|
||||
{_x("Network"), _x("UI"), _x("Service"), _x("Update"), _x("Tunnels"),
|
||||
_x("Clients"), _x("Peers"), _x("Keyring"), _x("Logging"), _x("Stats"),
|
||||
_x("Advanced") };
|
||||
_x("Reseeding"), _x("Advanced") };
|
||||
|
||||
public void renderNavBar(String requestURI) throws IOException {
|
||||
StringBuilder buf = new StringBuilder(1024);
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.RouterAddress;
|
||||
import net.i2p.router.CommSystemFacade;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.transport.Addresses;
|
||||
import net.i2p.router.transport.TransportManager;
|
||||
import net.i2p.router.transport.udp.UDPAddress;
|
||||
import net.i2p.router.transport.udp.UDPTransport;
|
||||
import net.i2p.time.Timestamper;
|
||||
import net.i2p.util.Addresses;
|
||||
|
||||
public class ConfigNetHelper extends HelperBase {
|
||||
public ConfigNetHelper() {}
|
||||
@@ -147,7 +149,8 @@ public class ConfigNetHelper extends HelperBase {
|
||||
}
|
||||
|
||||
public String[] getAddresses() {
|
||||
return Addresses.getAddresses();
|
||||
ArrayList<String> al = new ArrayList(Addresses.getAddresses());
|
||||
return al.toArray(new String[al.size()]);
|
||||
}
|
||||
|
||||
public String getInboundRate() {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.router.networkdb.reseed.Reseeder;
|
||||
|
||||
/**
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public class ConfigReseedHandler extends FormHandler {
|
||||
private Map _settings;
|
||||
|
||||
@Override
|
||||
protected void processForm() {
|
||||
|
||||
if (_action.equals(_("Save changes and reseed now"))) {
|
||||
saveChanges();
|
||||
boolean reseedInProgress = Boolean.valueOf(System.getProperty("net.i2p.router.web.ReseedHandler.reseedInProgress")).booleanValue();
|
||||
if (reseedInProgress) {
|
||||
addFormError(_("Reseeding is already in progress"));
|
||||
} else {
|
||||
// skip the nonce checking in ReseedHandler
|
||||
addFormNotice(_("Starting reseed process"));
|
||||
(new ReseedHandler(_context)).requestReseed();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (_action.equals(_("Save changes"))) {
|
||||
saveChanges();
|
||||
return;
|
||||
}
|
||||
addFormError(_("Unsupported") + ' ' + _action + '.');
|
||||
}
|
||||
|
||||
public void setSettings(Map settings) { _settings = new HashMap(settings); }
|
||||
|
||||
/** curses Jetty for returning arrays */
|
||||
private String getJettyString(String key) {
|
||||
String[] arr = (String[]) _settings.get(key);
|
||||
if (arr == null)
|
||||
return null;
|
||||
return arr[0].trim();
|
||||
}
|
||||
|
||||
private void saveChanges() {
|
||||
String port = getJettyString("port");
|
||||
if (port != null)
|
||||
_context.router().setConfigSetting(Reseeder.PROP_PROXY_PORT, port);
|
||||
String host = getJettyString("host");
|
||||
if (host != null)
|
||||
_context.router().setConfigSetting(Reseeder.PROP_PROXY_HOST, host);
|
||||
String url = getJettyString("reseedURL");
|
||||
if (url != null)
|
||||
_context.router().setConfigSetting(Reseeder.PROP_RESEED_URL, url.trim().replace("\r\n", ",").replace("\n", ","));
|
||||
String mode = getJettyString("mode");
|
||||
boolean req = "1".equals(mode);
|
||||
boolean disabled = "2".equals(mode);
|
||||
_context.router().setConfigSetting(Reseeder.PROP_SSL_REQUIRED,
|
||||
Boolean.toString(req));
|
||||
_context.router().setConfigSetting(Reseeder.PROP_SSL_DISABLE,
|
||||
Boolean.toString(disabled));
|
||||
boolean proxy = getJettyString("enable") != null;
|
||||
_context.router().setConfigSetting(Reseeder.PROP_PROXY_ENABLE, Boolean.toString(proxy));
|
||||
_context.router().saveConfig();
|
||||
addFormNotice(_("Configuration saved successfully."));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.router.networkdb.reseed.Reseeder;
|
||||
|
||||
/**
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public class ConfigReseedHelper extends HelperBase {
|
||||
|
||||
public String getPort() {
|
||||
return _context.getProperty(Reseeder.PROP_PROXY_PORT, "");
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return _context.getProperty(Reseeder.PROP_PROXY_HOST, "");
|
||||
}
|
||||
|
||||
public String modeChecked(int mode) {
|
||||
boolean required = _context.getBooleanProperty(Reseeder.PROP_SSL_REQUIRED);
|
||||
boolean disabled = _context.getBooleanProperty(Reseeder.PROP_SSL_DISABLE);
|
||||
if ((mode == 0 && (!disabled) && (!required)) ||
|
||||
(mode == 1 && (!disabled) && required) ||
|
||||
(mode == 2 && disabled))
|
||||
return "checked=\"true\"";
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getEnable() {
|
||||
boolean enabled = _context.getBooleanProperty(Reseeder.PROP_PROXY_ENABLE);
|
||||
if (enabled)
|
||||
return "checked=\"true\"";
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getReseedURL() {
|
||||
String urls = _context.getProperty(Reseeder.PROP_RESEED_URL, Reseeder.DEFAULT_SEED_URL + ',' + Reseeder.DEFAULT_SSL_SEED_URL);
|
||||
StringTokenizer tok = new StringTokenizer(urls, " ,\r\n");
|
||||
List<String> URLList = new ArrayList(16);
|
||||
while (tok.hasMoreTokens()) {
|
||||
String s = tok.nextToken().trim();
|
||||
if (s.length() > 0)
|
||||
URLList.add(s);
|
||||
}
|
||||
Collections.sort(URLList);
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (String s : URLList) {
|
||||
if (buf.length() > 0)
|
||||
buf.append('\n');
|
||||
buf.append(s);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
@@ -139,6 +139,6 @@ public class ConfigStatsHelper extends HelperBase {
|
||||
public boolean getCurrentCanBeGraphed() { return _currentCanBeGraphed; }
|
||||
public String getExplicitFilter() { return _filter; }
|
||||
public boolean getIsFull() {
|
||||
return _context.getBooleanPropertyDefaultTrue(StatManager.PROP_STAT_FULL);
|
||||
return _context.getBooleanProperty(StatManager.PROP_STAT_FULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.i2p.router.web;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.TrustedUpdate;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.FileUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -61,14 +62,10 @@ public class ConfigUpdateHandler extends FormHandler {
|
||||
|
||||
public static final String DEFAULT_UPDATE_URL;
|
||||
static {
|
||||
String foo;
|
||||
try {
|
||||
Class.forName("java.util.jar.Pack200", false, ClassLoader.getSystemClassLoader());
|
||||
foo = PACK200_URLS;
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
foo = NO_PACK200_URLS;
|
||||
}
|
||||
DEFAULT_UPDATE_URL = foo;
|
||||
if (FileUtil.isPack200Supported())
|
||||
DEFAULT_UPDATE_URL = PACK200_URLS;
|
||||
else
|
||||
DEFAULT_UPDATE_URL = NO_PACK200_URLS;
|
||||
}
|
||||
|
||||
public static final String PROP_TRUSTED_KEYS = "router.trustedUpdateKeys";
|
||||
|
||||
@@ -59,7 +59,13 @@ public class GraphHelper extends FormHandler {
|
||||
try { _width = Math.min(Integer.parseInt(str), MAX_X); } catch (NumberFormatException nfe) {}
|
||||
}
|
||||
public void setRefreshDelay(String str) {
|
||||
try { _refreshDelaySeconds = Math.max(Integer.parseInt(str), MIN_REFRESH); } catch (NumberFormatException nfe) {}
|
||||
try {
|
||||
int rds = Integer.parseInt(str);
|
||||
if (rds > 0)
|
||||
_refreshDelaySeconds = Math.max(rds, MIN_REFRESH);
|
||||
else
|
||||
_refreshDelaySeconds = -1;
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
|
||||
public String getImages() {
|
||||
@@ -83,7 +89,7 @@ public class GraphHelper extends FormHandler {
|
||||
+ "&periodCount=" + (3 * _periodCount )
|
||||
+ "&width=" + (3 * _width)
|
||||
+ "&height=" + (3 * _height)
|
||||
+ "\" / target=\"_blank\">");
|
||||
+ "\" target=\"_blank\">");
|
||||
String title = _("Combined bandwidth graph");
|
||||
_out.write("<img class=\"statimage\" width=\""
|
||||
+ (_width + 83) + "\" height=\"" + (_height + 92)
|
||||
@@ -129,6 +135,8 @@ public class GraphHelper extends FormHandler {
|
||||
return "";
|
||||
}
|
||||
|
||||
private static final int[] times = { 60, 2*60, 5*60, 10*60, 30*60, 60*60, -1 };
|
||||
|
||||
public String getForm() {
|
||||
String prev = System.getProperty("net.i2p.router.web.GraphHelper.nonce");
|
||||
if (prev != null) System.setProperty("net.i2p.router.web.GraphHelper.noncePrev", prev);
|
||||
@@ -145,8 +153,22 @@ public class GraphHelper extends FormHandler {
|
||||
_out.write(_("Image sizes") + ": " + _("width") + ": <input size=\"4\" type=\"text\" name=\"width\" value=\"" + _width
|
||||
+ "\"> " + _("pixels") + ", " + _("height") + ": <input size=\"4\" type=\"text\" name=\"height\" value=\"" + _height
|
||||
+ "\"> " + _("pixels") + "<br>\n");
|
||||
_out.write(_("Refresh delay") + ": <select name=\"refreshDelay\"><option value=\"60\">1 " + _("minute") + "</option><option value=\"120\">2 " + _("minutes") + "</option><option value=\"300\">5 " + _("minutes") + "</option><option value=\"600\">10 " + _("minutes") + "</option><option value=\"1800\">30 " + _("minutes") + "</option><option value=\"3600\">1 " + _("hour") + "</option><option value=\"-1\">" + _("Never") + "</option></select><br>\n");
|
||||
_out.write("<hr><div class=\"formaction\"><input type=\"submit\" value=\"" + _("Redraw") + "\"></div></form>");
|
||||
_out.write(_("Refresh delay") + ": <select name=\"refreshDelay\">");
|
||||
for (int i = 0; i < times.length; i++) {
|
||||
_out.write("<option value=\"");
|
||||
_out.write(Integer.toString(times[i]));
|
||||
_out.write("\"");
|
||||
if (times[i] == _refreshDelaySeconds)
|
||||
_out.write(" selected=\"true\"");
|
||||
_out.write(">");
|
||||
if (times[i] > 0)
|
||||
_out.write(DataHelper.formatDuration2(times[i] * 1000));
|
||||
else
|
||||
_out.write(_("Never"));
|
||||
_out.write("</option>\n");
|
||||
}
|
||||
_out.write("</select><br>\n" +
|
||||
"<hr><div class=\"formaction\"><input type=\"submit\" value=\"" + _("Redraw") + "\"></div></form>");
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -53,7 +53,8 @@ public class LocaleWebAppHandler extends WebApplicationHandler
|
||||
// home page
|
||||
pathInContext = "/index.jsp";
|
||||
} else if (pathInContext.indexOf("/", 1) < 0 &&
|
||||
!pathInContext.endsWith(".jsp")) {
|
||||
(!pathInContext.endsWith(".jsp")) &&
|
||||
(!pathInContext.endsWith(".txt"))) {
|
||||
// add .jsp to pages at top level
|
||||
pathInContext += ".jsp";
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ public class PluginUpdateHandler extends UpdateHandler {
|
||||
}
|
||||
buf.append(": ");
|
||||
buf.append(_("{0}B transferred", DataHelper.formatSize2(currentWrite + alreadyTransferred)));
|
||||
buf.append("</b>");
|
||||
updateStatus(buf.toString());
|
||||
}
|
||||
|
||||
|
||||
@@ -4,37 +4,54 @@ import java.util.ArrayList;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStore;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.apps.systray.SysTray;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
import net.i2p.util.ShellCommand;
|
||||
|
||||
import org.mortbay.http.DigestAuthenticator;
|
||||
import org.mortbay.http.HashUserRealm;
|
||||
import org.mortbay.http.NCSARequestLog;
|
||||
import org.mortbay.http.SecurityConstraint;
|
||||
import org.mortbay.http.SslListener;
|
||||
import org.mortbay.http.handler.SecurityHandler;
|
||||
import org.mortbay.jetty.Server;
|
||||
import org.mortbay.jetty.servlet.WebApplicationContext;
|
||||
import org.mortbay.jetty.servlet.WebApplicationHandler;
|
||||
import org.mortbay.util.InetAddrPort;
|
||||
|
||||
public class RouterConsoleRunner {
|
||||
private Server _server;
|
||||
private String _listenPort = "7657";
|
||||
private String _listenHost = "127.0.0.1";
|
||||
private String _webAppsDir = "./webapps/";
|
||||
private String _listenPort;
|
||||
private String _listenHost;
|
||||
private String _sslListenPort;
|
||||
private String _sslListenHost;
|
||||
private String _webAppsDir;
|
||||
private static final String PROP_WEBAPP_CONFIG_FILENAME = "router.webappsConfigFile";
|
||||
private static final String DEFAULT_WEBAPP_CONFIG_FILENAME = "webapps.config";
|
||||
private static final DigestAuthenticator authenticator = new DigestAuthenticator();
|
||||
public static final String ROUTERCONSOLE = "routerconsole";
|
||||
public static final String PREFIX = "webapps.";
|
||||
public static final String ENABLED = ".startOnLoad";
|
||||
private static final String PROP_KEYSTORE_PASSWORD = "routerconsole.keystorePassword";
|
||||
private static final String DEFAULT_KEYSTORE_PASSWORD = "changeit";
|
||||
private static final String PROP_KEY_PASSWORD = "routerconsole.keyPassword";
|
||||
private static final String DEFAULT_LISTEN_PORT = "7657";
|
||||
private static final String DEFAULT_LISTEN_HOST = "127.0.0.1";
|
||||
private static final String DEFAULT_WEBAPPS_DIR = "./webapps/";
|
||||
private static final String USAGE = "Bad RouterConsoleRunner arguments, check clientApp.0.args in your clients.config file! " +
|
||||
"Usage: [[port host[,host]] [-s sslPort [host[,host]]] [webAppsDir]]";
|
||||
|
||||
static {
|
||||
System.setProperty("org.mortbay.http.Version.paranoid", "true");
|
||||
@@ -42,6 +59,27 @@ public class RouterConsoleRunner {
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* non-SSL:
|
||||
* RouterConsoleRunner
|
||||
* RouterConsoleRunner 7657
|
||||
* RouterConsoleRunner 7657 127.0.0.1
|
||||
* RouterConsoleRunner 7657 127.0.0.1,::1
|
||||
* RouterConsoleRunner 7657 127.0.0.1,::1 ./webapps/
|
||||
*
|
||||
* SSL:
|
||||
* RouterConsoleRunner -s 7657
|
||||
* RouterConsoleRunner -s 7657 127.0.0.1
|
||||
* RouterConsoleRunner -s 7657 127.0.0.1,::1
|
||||
* RouterConsoleRunner -s 7657 127.0.0.1,::1 ./webapps/
|
||||
*
|
||||
* If using both, non-SSL must be first:
|
||||
* RouterConsoleRunner 7657 127.0.0.1 -s 7667
|
||||
* RouterConsoleRunner 7657 127.0.0.1 -s 7667 127.0.0.1
|
||||
* RouterConsoleRunner 7657 127.0.0.1,::1 -s 7667 127.0.0.1,::1
|
||||
* RouterConsoleRunner 7657 127.0.0.1,::1 -s 7667 127.0.0.1,::1 ./webapps/
|
||||
* </pre>
|
||||
*
|
||||
* @param args second arg may be a comma-separated list of bind addresses,
|
||||
* for example ::1,127.0.0.1
|
||||
* On XP, the other order (127.0.0.1,::1) fails the IPV6 bind,
|
||||
@@ -50,10 +88,40 @@ public class RouterConsoleRunner {
|
||||
* So the wise choice is ::1,127.0.0.1
|
||||
*/
|
||||
public RouterConsoleRunner(String args[]) {
|
||||
if (args.length == 3) {
|
||||
_listenPort = args[0].trim();
|
||||
_listenHost = args[1].trim();
|
||||
_webAppsDir = args[2].trim();
|
||||
if (args.length == 0) {
|
||||
// _listenHost and _webAppsDir are defaulted below
|
||||
_listenPort = DEFAULT_LISTEN_PORT;
|
||||
} else {
|
||||
boolean ssl = false;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].equals("-s"))
|
||||
ssl = true;
|
||||
else if ((!ssl) && _listenPort == null)
|
||||
_listenPort = args[i];
|
||||
else if ((!ssl) && _listenHost == null)
|
||||
_listenHost = args[i];
|
||||
else if (ssl && _sslListenPort == null)
|
||||
_sslListenPort = args[i];
|
||||
else if (ssl && _sslListenHost == null)
|
||||
_sslListenHost = args[i];
|
||||
else if (_webAppsDir == null)
|
||||
_webAppsDir = args[i];
|
||||
else {
|
||||
System.err.println(USAGE);
|
||||
throw new IllegalArgumentException(USAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_listenHost == null)
|
||||
_listenHost = DEFAULT_LISTEN_HOST;
|
||||
if (_sslListenHost == null)
|
||||
_sslListenHost = _listenHost;
|
||||
if (_webAppsDir == null)
|
||||
_webAppsDir = DEFAULT_WEBAPPS_DIR;
|
||||
// _listenPort and _sslListenPort are not defaulted, if one or the other is null, do not enable
|
||||
if (_listenPort == null && _sslListenPort == null) {
|
||||
System.err.println(USAGE);
|
||||
throw new IllegalArgumentException(USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +142,18 @@ public class RouterConsoleRunner {
|
||||
// so Jetty can find WebAppConfiguration
|
||||
System.setProperty("jetty.class.path", I2PAppContext.getGlobalContext().getBaseDir() + "/lib/routerconsole.jar");
|
||||
_server = new Server();
|
||||
|
||||
String log = I2PAppContext.getGlobalContext().getProperty("routerconsole.log");
|
||||
if (log != null) {
|
||||
File logFile = new File(log);
|
||||
if (!logFile.isAbsolute())
|
||||
logFile = new File(I2PAppContext.getGlobalContext().getLogDir(), "logs/" + log);
|
||||
try {
|
||||
_server.setRequestLog(new NCSARequestLog(logFile.getAbsolutePath()));
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("ERROR: Unable to create Jetty log: " + ioe);
|
||||
}
|
||||
}
|
||||
boolean rewrite = false;
|
||||
Properties props = webAppProperties();
|
||||
if (props.isEmpty()) {
|
||||
@@ -96,27 +176,69 @@ public class RouterConsoleRunner {
|
||||
List<String> notStarted = new ArrayList();
|
||||
WebApplicationHandler baseHandler = null;
|
||||
try {
|
||||
StringTokenizer tok = new StringTokenizer(_listenHost, " ,");
|
||||
int boundAddresses = 0;
|
||||
while (tok.hasMoreTokens()) {
|
||||
String host = tok.nextToken().trim();
|
||||
try {
|
||||
if (host.indexOf(":") >= 0) // IPV6 - requires patched Jetty 5
|
||||
_server.addListener('[' + host + "]:" + _listenPort);
|
||||
else
|
||||
_server.addListener(host + ':' + _listenPort);
|
||||
boundAddresses++;
|
||||
} catch (IOException ioe) { // this doesn't seem to work, exceptions don't happen until start() below
|
||||
System.err.println("Unable to bind routerconsole to " + host + " port " + _listenPort + ' ' + ioe);
|
||||
|
||||
// add standard listeners
|
||||
if (_listenPort != null) {
|
||||
StringTokenizer tok = new StringTokenizer(_listenHost, " ,");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String host = tok.nextToken().trim();
|
||||
try {
|
||||
if (host.indexOf(":") >= 0) // IPV6 - requires patched Jetty 5
|
||||
_server.addListener('[' + host + "]:" + _listenPort);
|
||||
else
|
||||
_server.addListener(host + ':' + _listenPort);
|
||||
boundAddresses++;
|
||||
} catch (IOException ioe) { // this doesn't seem to work, exceptions don't happen until start() below
|
||||
System.err.println("Unable to bind routerconsole to " + host + " port " + _listenPort + ' ' + ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add SSL listeners
|
||||
int sslPort = 0;
|
||||
if (_sslListenPort != null) {
|
||||
try {
|
||||
sslPort = Integer.parseInt(_sslListenPort);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
if (sslPort <= 0)
|
||||
System.err.println("Bad routerconsole SSL port " + _sslListenPort);
|
||||
}
|
||||
if (sslPort > 0) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
File keyStore = new File(ctx.getConfigDir(), "keystore/console.ks");
|
||||
if (verifyKeyStore(keyStore)) {
|
||||
StringTokenizer tok = new StringTokenizer(_sslListenHost, " ,");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String host = tok.nextToken().trim();
|
||||
// doing it this way means we don't have to escape an IPv6 host with []
|
||||
InetAddrPort iap = new InetAddrPort(host, sslPort);
|
||||
try {
|
||||
SslListener ssll = new SslListener(iap);
|
||||
// the keystore path and password
|
||||
ssll.setKeystore(keyStore.getAbsolutePath());
|
||||
ssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD));
|
||||
// the X.509 cert password (if not present, verifyKeyStore() returned false)
|
||||
ssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork"));
|
||||
_server.addListener(ssll);
|
||||
boundAddresses++;
|
||||
} catch (Exception e) { // probably no exceptions at this point
|
||||
System.err.println("Unable to bind routerconsole to " + host + " port " + sslPort + " for SSL: " + e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.err.println("Unable to create or access keystore for SSL: " + keyStore.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
if (boundAddresses <= 0) {
|
||||
System.err.println("Unable to bind routerconsole to any address on port " + _listenPort);
|
||||
System.err.println("Unable to bind routerconsole to any address on port " + _listenPort + (sslPort > 0 ? (" or SSL port " + sslPort) : ""));
|
||||
return;
|
||||
}
|
||||
_server.setRootWebApp(ROUTERCONSOLE);
|
||||
WebApplicationContext wac = _server.addWebApplication("/", _webAppsDir + ROUTERCONSOLE + ".war");
|
||||
File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" + _listenPort);
|
||||
File tmpdir = new SecureDirectory(workDir, ROUTERCONSOLE + "-" +
|
||||
(_listenPort != null ? _listenPort : _sslListenPort));
|
||||
tmpdir.mkdir();
|
||||
wac.setTempDirectory(tmpdir);
|
||||
baseHandler = new LocaleWebAppHandler(I2PAppContext.getGlobalContext());
|
||||
@@ -131,7 +253,8 @@ public class RouterConsoleRunner {
|
||||
String enabled = props.getProperty(PREFIX + appName + ENABLED);
|
||||
if (! "false".equals(enabled)) {
|
||||
String path = new File(dir, fileNames[i]).getCanonicalPath();
|
||||
tmpdir = new SecureDirectory(workDir, appName + "-" + _listenPort);
|
||||
tmpdir = new SecureDirectory(workDir, appName + "-" +
|
||||
(_listenPort != null ? _listenPort : _sslListenPort));
|
||||
WebAppStarter.addWebApp(I2PAppContext.getGlobalContext(), _server, appName, path, tmpdir);
|
||||
|
||||
if (enabled == null) {
|
||||
@@ -201,6 +324,90 @@ public class RouterConsoleRunner {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return success if it exists and we have a password, or it was created successfully.
|
||||
* @since 0.8.3
|
||||
*/
|
||||
private static boolean verifyKeyStore(File ks) {
|
||||
if (ks.exists()) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
boolean rv = ctx.getProperty(PROP_KEY_PASSWORD) != null;
|
||||
if (!rv)
|
||||
System.err.println("Console SSL error, must set " + PROP_KEY_PASSWORD + " in " + (new File(ctx.getConfigDir(), "router.config")).getAbsolutePath());
|
||||
return rv;
|
||||
}
|
||||
File dir = ks.getParentFile();
|
||||
if (!dir.exists()) {
|
||||
File sdir = new SecureDirectory(dir.getAbsolutePath());
|
||||
if (!sdir.mkdir())
|
||||
return false;
|
||||
}
|
||||
return createKeyStore(ks);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call out to keytool to create a new keystore with a keypair in it.
|
||||
* Trying to do this programatically is a nightmare, requiring either BouncyCastle
|
||||
* libs or using proprietary Sun libs, and it's a huge mess.
|
||||
*
|
||||
* @return success
|
||||
* @since 0.8.3
|
||||
*/
|
||||
private static boolean createKeyStore(File ks) {
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
// make a random 48 character password (30 * 8 / 5)
|
||||
byte[] rand = new byte[30];
|
||||
ctx.random().nextBytes(rand);
|
||||
String keyPassword = Base32.encode(rand);
|
||||
// and one for the cname
|
||||
ctx.random().nextBytes(rand);
|
||||
String cname = Base32.encode(rand) + ".console.i2p.net";
|
||||
|
||||
String keytool = (new File(System.getProperty("java.home"), "bin/keytool")).getAbsolutePath();
|
||||
String[] args = new String[] {
|
||||
keytool,
|
||||
"-genkey", // -genkeypair preferred in newer keytools, but this works with more
|
||||
"-storetype", KeyStore.getDefaultType(),
|
||||
"-keystore", ks.getAbsolutePath(),
|
||||
"-storepass", DEFAULT_KEYSTORE_PASSWORD,
|
||||
"-alias", "console",
|
||||
"-dname", "CN=" + cname + ",OU=Console,O=I2P Anonymous Network,L=XX,ST=XX,C=XX",
|
||||
"-validity", "3652", // 10 years
|
||||
"-keyalg", "DSA",
|
||||
"-keysize", "1024",
|
||||
"-keypass", keyPassword};
|
||||
boolean success = (new ShellCommand()).executeSilentAndWaitTimed(args, 30); // 30 secs
|
||||
if (success) {
|
||||
success = ks.exists();
|
||||
if (success) {
|
||||
SecureFileOutputStream.setPerms(ks);
|
||||
try {
|
||||
RouterContext rctx = (RouterContext) ctx;
|
||||
rctx.router().setConfigSetting(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD);
|
||||
rctx.router().setConfigSetting(PROP_KEY_PASSWORD, keyPassword);
|
||||
rctx.router().saveConfig();
|
||||
} catch (Exception e) {} // class cast exception
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
System.err.println("Created self-signed certificate for " + cname + " in keystore: " + ks.getAbsolutePath() + "\n" +
|
||||
"The certificate name was generated randomly, and is not associated with your " +
|
||||
"IP address, host name, router identity, or destination keys.");
|
||||
} else {
|
||||
System.err.println("Failed to create console SSL keystore using command line:");
|
||||
StringBuilder buf = new StringBuilder(256);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
buf.append('"').append(args[i]).append("\" ");
|
||||
}
|
||||
System.err.println(buf.toString());
|
||||
System.err.println("This is for the Sun/Oracle keytool, others may be incompatible.\n" +
|
||||
"If you create the keystore manually, you must add " + PROP_KEYSTORE_PASSWORD + " and " + PROP_KEY_PASSWORD +
|
||||
" to " + (new File(ctx.getConfigDir(), "router.config")).getAbsolutePath());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static void initialize(WebApplicationContext context) {
|
||||
String password = getPassword();
|
||||
if (password != null) {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
@@ -15,10 +18,12 @@ import net.i2p.router.RouterVersion;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.PartialEepGet;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
/**
|
||||
* <p>Handles the request to update the router by firing off an
|
||||
* {@link net.i2p.util.EepGet} call to download the latest signed update file
|
||||
* <p>Handles the request to update the router by firing one or more
|
||||
* {@link net.i2p.util.EepGet} calls to download the latest signed update file
|
||||
* and displaying the status to anyone who asks.
|
||||
* </p>
|
||||
* <p>After the download completes the signed update file is verified with
|
||||
@@ -125,6 +130,11 @@ public class UpdateHandler {
|
||||
protected boolean done;
|
||||
protected EepGet _get;
|
||||
protected final DecimalFormat _pct = new DecimalFormat("0.0%");
|
||||
/** tells the listeners what mode we are in */
|
||||
private boolean _isPartial;
|
||||
/** set by the listeners on completion */
|
||||
private boolean _isNewer;
|
||||
private ByteArrayOutputStream _baos;
|
||||
|
||||
public UpdateRunner() {
|
||||
_isRunning = false;
|
||||
@@ -141,39 +151,88 @@ public class UpdateHandler {
|
||||
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
|
||||
_isRunning = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop through the entire list of update URLs.
|
||||
* For each one, first get the version from the first 56 bytes and see if
|
||||
* it is newer than what we are running now.
|
||||
* If it is, get the whole thing.
|
||||
*/
|
||||
protected void update() {
|
||||
updateStatus("<b>" + _("Updating") + "</b>");
|
||||
// TODO:
|
||||
// Do a PartialEepGet on the selected URL, check for version we expect,
|
||||
// and loop if it isn't what we want.
|
||||
// This will allow us to do a release without waiting for the last host to install the update.
|
||||
// Alternative: In bytesTransferred(), Check the data in the output file after
|
||||
// we've received at least 56 bytes. Need a cancel() method in EepGet ?
|
||||
String updateURL = selectUpdateURL();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Selected update URL: " + updateURL);
|
||||
|
||||
boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
|
||||
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
|
||||
int proxyPort = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT);
|
||||
try {
|
||||
if (shouldProxy)
|
||||
// 40 retries!!
|
||||
_get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, updateURL, false);
|
||||
else
|
||||
_get = new EepGet(_context, 1, _updateFile, updateURL, false);
|
||||
_get.addStatusListener(UpdateRunner.this);
|
||||
_get.fetch();
|
||||
} catch (Throwable t) {
|
||||
_log.error("Error updating", t);
|
||||
|
||||
List<String> urls = getUpdateURLs();
|
||||
if (urls.isEmpty()) {
|
||||
// not likely, don't bother translating
|
||||
updateStatus("<b>Update source list is empty, cannot download update</b>");
|
||||
_log.log(Log.CRIT, "Update source list is empty - cannot download update");
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldProxy)
|
||||
_baos = new ByteArrayOutputStream(TrustedUpdate.HEADER_BYTES);
|
||||
for (String updateURL : urls) {
|
||||
updateStatus("<b>" + _("Updating from {0}", linkify(updateURL)) + "</b>");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Selected update URL: " + updateURL);
|
||||
|
||||
// Check the first 56 bytes for the version
|
||||
if (shouldProxy) {
|
||||
_isPartial = true;
|
||||
_isNewer = false;
|
||||
_baos.reset();
|
||||
try {
|
||||
// no retries
|
||||
_get = new PartialEepGet(_context, proxyHost, proxyPort, _baos, updateURL, TrustedUpdate.HEADER_BYTES);
|
||||
_get.addStatusListener(UpdateRunner.this);
|
||||
_get.fetch();
|
||||
} catch (Throwable t) {
|
||||
_isNewer = false;
|
||||
}
|
||||
_isPartial = false;
|
||||
if (!_isNewer)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now get the whole thing
|
||||
try {
|
||||
if (shouldProxy)
|
||||
// 40 retries!!
|
||||
_get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, updateURL, false);
|
||||
else
|
||||
_get = new EepGet(_context, 1, _updateFile, updateURL, false);
|
||||
_get.addStatusListener(UpdateRunner.this);
|
||||
_get.fetch();
|
||||
} catch (Throwable t) {
|
||||
_log.error("Error updating", t);
|
||||
}
|
||||
if (this.done)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// EepGet Listeners below.
|
||||
// We use the same for both the partial and the full EepGet,
|
||||
// with a couple of adjustments depending on which mode.
|
||||
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
||||
_isNewer = false;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Attempt failed on " + url, cause);
|
||||
// ignored
|
||||
}
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
||||
if (_isPartial)
|
||||
return;
|
||||
StringBuilder buf = new StringBuilder(64);
|
||||
buf.append("<b>").append(_("Updating")).append("</b> ");
|
||||
double pct = ((double)alreadyTransferred + (double)currentWrite) /
|
||||
@@ -186,6 +245,19 @@ public class UpdateHandler {
|
||||
updateStatus(buf.toString());
|
||||
}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
|
||||
if (_isPartial) {
|
||||
// Compare version with what we have now
|
||||
String newVersion = TrustedUpdate.getVersionString(new ByteArrayInputStream(_baos.toByteArray()));
|
||||
boolean newer = (new VersionComparator()).compare(newVersion, RouterVersion.VERSION) > 0;
|
||||
if (!newer) {
|
||||
updateStatus("<b>" + _("No new version found at {0}", linkify(url)) + "</b>");
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Found old version \"" + newVersion + "\" at " + url);
|
||||
}
|
||||
_isNewer = newer;
|
||||
return;
|
||||
}
|
||||
// Process the .sud/.su2 file
|
||||
updateStatus("<b>" + _("Update downloaded") + "</b>");
|
||||
TrustedUpdate up = new TrustedUpdate(_context);
|
||||
File f = new File(_updateFile);
|
||||
@@ -223,15 +295,16 @@ public class UpdateHandler {
|
||||
}
|
||||
} else {
|
||||
_log.log(Log.CRIT, err + " from " + url);
|
||||
updateStatus("<b>" + err + ' ' + _("from {0}", url) + " </b>");
|
||||
updateStatus("<b>" + err + ' ' + _("from {0}", linkify(url)) + " </b>");
|
||||
}
|
||||
}
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||
_isNewer = false;
|
||||
// don't display bytesTransferred as it is meaningless
|
||||
_log.log(Log.CRIT, "Update from " + url + " did not download completely (" +
|
||||
_log.error("Update from " + url + " did not download completely (" +
|
||||
bytesRemaining + " remaining after " + currentAttempt + " tries)");
|
||||
|
||||
updateStatus("<b>" + _("Transfer failed") + "</b>");
|
||||
updateStatus("<b>" + _("Transfer failed from {0}", linkify(url)) + "</b>");
|
||||
}
|
||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||
public void attempting(String url) {}
|
||||
@@ -242,27 +315,24 @@ public class UpdateHandler {
|
||||
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
|
||||
}
|
||||
|
||||
private String selectUpdateURL() {
|
||||
private List<String> getUpdateURLs() {
|
||||
String URLs = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
|
||||
StringTokenizer tok = new StringTokenizer(URLs, " ,\r\n");
|
||||
List URLList = new ArrayList();
|
||||
List<String> URLList = new ArrayList();
|
||||
while (tok.hasMoreTokens())
|
||||
URLList.add(tok.nextToken().trim());
|
||||
int size = URLList.size();
|
||||
//_log.log(Log.DEBUG, "Picking update source from " + size + " candidates.");
|
||||
if (size <= 0) {
|
||||
_log.log(Log.CRIT, "Update source list is empty - cannot download update");
|
||||
return null;
|
||||
}
|
||||
int index = I2PAppContext.getGlobalContext().random().nextInt(size);
|
||||
_log.log(Log.DEBUG, "Picked update source " + index + ".");
|
||||
return (String) URLList.get(index);
|
||||
Collections.shuffle(URLList, _context.random());
|
||||
return URLList;
|
||||
}
|
||||
|
||||
protected void updateStatus(String s) {
|
||||
_status = s;
|
||||
}
|
||||
|
||||
protected static String linkify(String url) {
|
||||
return "<a target=\"_blank\" href=\"" + url + "\"/>" + url + "</a>";
|
||||
}
|
||||
|
||||
/** translate a string */
|
||||
protected String _(String s) {
|
||||
return Messages.getString(s, _context);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigAdvancedHandler.nonce")%>" >
|
||||
<input type="hidden" name="action" value="blah" >
|
||||
<h3><%=intl._("Advanced I2P Configuration")%></h3>
|
||||
<textarea rows="32" cols="60" name="config" wrap="off"><jsp:getProperty name="advancedhelper" property="settings" /></textarea><br><hr>
|
||||
<textarea rows="32" cols="60" name="config" wrap="off" spellcheck="false"><jsp:getProperty name="advancedhelper" property="settings" /></textarea><br><hr>
|
||||
<div class="formaction">
|
||||
<input type="reset" value="<%=intl._("Cancel")%>" >
|
||||
<input type="submit" name="shouldsave" value="<%=intl._("Save changes")%>" >
|
||||
|
||||
@@ -47,7 +47,51 @@ button span.hide{
|
||||
<input type="submit" name="edit" value="<%=intl._("Add Client")%>" />
|
||||
<% } %>
|
||||
<input type="submit" name="action" value="<%=intl._("Save Client Configuration")%>" />
|
||||
</div></div><h3><a name="webapp"></a><%=intl._("WebApp Configuration")%></h3><p>
|
||||
</div></div>
|
||||
|
||||
<h3><a name="i2cp"></a><%=intl._("Advanced Client Interface Configuration")%></h3><p>
|
||||
<b><%=intl._("External I2CP (I2P Client Protocol) Interface Configuration")%></b><br>
|
||||
<input type="radio" class="optbox" name="mode" value="1" <%=clientshelper.i2cpModeChecked(1) %> >
|
||||
<%=intl._("Enabled without SSL")%><br>
|
||||
<input type="radio" class="optbox" name="mode" value="2" <%=clientshelper.i2cpModeChecked(2) %> >
|
||||
<%=intl._("Enabled with SSL required")%><br>
|
||||
<input type="radio" class="optbox" name="mode" value="0" <%=clientshelper.i2cpModeChecked(0) %> >
|
||||
<%=intl._("Disabled - Clients outside this Java process may not connect")%><br>
|
||||
<%=intl._("I2CP Port")%>:
|
||||
<input name="port" type="text" size="5" maxlength="5" value="<jsp:getProperty name="clientshelper" property="port" />" ><br>
|
||||
<%=intl._("I2CP Interface")%>:
|
||||
<select name="interface">
|
||||
<%
|
||||
String[] ips = clientshelper.intfcAddresses();
|
||||
for (int i = 0; i < ips.length; i++) {
|
||||
out.print("<option value=\"");
|
||||
out.print(ips[i]);
|
||||
out.print('\"');
|
||||
if (clientshelper.isIFSelected(ips[i]))
|
||||
out.print(" selected=\"selected\"");
|
||||
out.print('>');
|
||||
out.print(ips[i]);
|
||||
out.print("</option>\n");
|
||||
}
|
||||
%>
|
||||
</select><br>
|
||||
<b><%=intl._("Authorization")%></b><br>
|
||||
<input type="checkbox" class="optbox" name="auth" value="true" <jsp:getProperty name="clientshelper" property="auth" /> >
|
||||
<%=intl._("Require username and password")%><br>
|
||||
<%=intl._("Username")%>:
|
||||
<input name="user" type="text" value="<jsp:getProperty name="clientshelper" property="user" />" ><br>
|
||||
<%=intl._("Password")%>:
|
||||
<input name="pw" type="password" value="<jsp:getProperty name="clientshelper" property="pw" />" ><br>
|
||||
</p><p><b><%=intl._("The default settings will work for most people.")%></b>
|
||||
<%=intl._("Any changes made here must also be configured in the external client.")%>
|
||||
<%=intl._("Many clients do not support SSL or authorization.")%>
|
||||
<i><%=intl._("All changes require restart to take effect.")%></i>
|
||||
</p><hr><div class="formaction">
|
||||
<input type="submit" name="foo" value="<%=intl._("Cancel")%>" />
|
||||
<input type="submit" name="action" value="<%=intl._("Save Interface Configuration")%>" />
|
||||
</div>
|
||||
|
||||
<h3><a name="webapp"></a><%=intl._("WebApp Configuration")%></h3><p>
|
||||
<%=intl._("The Java web applications listed below are started by the webConsole client and run in the same JVM as the router. They are usually web applications accessible through the router console. They may be complete applications (e.g. i2psnark),front-ends to another client or application which must be separately enabled (e.g. susidns, i2ptunnel), or have no web interface at all (e.g. addressbook).")%>
|
||||
</p><p>
|
||||
<%=intl._("A web app may also be disabled by removing the .war file from the webapps directory; however the .war file and web app will reappear when you update your router to a newer version, so disabling the web app here is the preferred method.")%>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<div class="wideload">
|
||||
<p><table><tr>
|
||||
<td class="mediumtags" align="right"><%=intl._("Dest. name, hash, or full key")%>:</td>
|
||||
<td><textarea name="peer" cols="44" rows="1" style="height: 3em;" wrap="off"></textarea></td>
|
||||
<td><textarea name="peer" cols="44" rows="1" style="height: 3em;" wrap="off" spellcheck="false"></textarea></td>
|
||||
</tr><tr>
|
||||
<td class="mediumtags" align="right"><%=intl._("Encryption Key")%>:</td>
|
||||
<td><input type="text" size="55" name="key" ></td>
|
||||
|
||||
59
apps/routerconsole/jsp/configreseed.jsp
Normal file
59
apps/routerconsole/jsp/configreseed.jsp
Normal file
@@ -0,0 +1,59 @@
|
||||
<%@page contentType="text/html"%>
|
||||
<%@page pageEncoding="UTF-8"%>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<html><head>
|
||||
<%@include file="css.jsi" %>
|
||||
<%=intl.title("config reseeding")%>
|
||||
</head><body>
|
||||
|
||||
<%@include file="summary.jsi" %>
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.ConfigReseedHelper" id="reseedHelper" scope="request" />
|
||||
<jsp:setProperty name="reseedHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<h1><%=intl._("I2P Reseeding Configuration")%></h1>
|
||||
<div class="main" id="main">
|
||||
<%@include file="confignav.jsi" %>
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.ConfigReseedHandler" id="formhandler" scope="request" />
|
||||
<% formhandler.storeMethod(request.getMethod()); %>
|
||||
<jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<jsp:setProperty name="formhandler" property="action" value="<%=request.getParameter("action")%>" />
|
||||
<jsp:setProperty name="formhandler" property="nonce" value="<%=request.getParameter("nonce")%>" />
|
||||
<jsp:setProperty name="formhandler" property="settings" value="<%=request.getParameterMap()%>" />
|
||||
<jsp:getProperty name="formhandler" property="allMessages" />
|
||||
<div class="configure"><form action="" method="POST">
|
||||
<% String prev = System.getProperty("net.i2p.router.web.ConfigReseedHandler.nonce");
|
||||
if (prev != null) System.setProperty("net.i2p.router.web.ConfigReseedHandler.noncePrev", prev);
|
||||
System.setProperty("net.i2p.router.web.ConfigReseedHandler.nonce", new java.util.Random().nextLong()+""); %>
|
||||
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigReseedHandler.nonce")%>" >
|
||||
<h3><%=intl._("Reseeding Configuration")%></h3>
|
||||
<p><%=intl._("Reseeding is the bootstrapping process used to find other routers when you first install I2P, or when your router has too few router references remaining.")%>
|
||||
<%=intl._("If reseeding has failed, you should first check your network connection.")%>
|
||||
<p><b><%=intl._("The default settings will work for most people.")%></b>
|
||||
<%=intl._("Change these only if HTTP is blocked by a restrictive firewall, reseed has failed, and you have access to an HTTP proxy.")%>
|
||||
<%=intl._("See {0} for instructions on reseeding manually.", "<a href=\"http://www.i2p2.de/faq.html#manual_reseed\">" + intl._("the FAQ") + "</a>")%>
|
||||
</p>
|
||||
<div class="wideload">
|
||||
<table border="0" cellspacing="5">
|
||||
<tr><td class="mediumtags" align="right"><b><%=intl._("Reseed URL Selection")%></b></td>
|
||||
<td><input type="radio" class="optbox" name="mode" value="0" <%=reseedHelper.modeChecked(0) %> >
|
||||
<%=intl._("Try SSL first then non-SSL")%>
|
||||
<input type="radio" class="optbox" name="mode" value="1" <%=reseedHelper.modeChecked(1) %> >
|
||||
<%=intl._("Use SSL only")%>
|
||||
<input type="radio" class="optbox" name="mode" value="2" <%=reseedHelper.modeChecked(2) %> >
|
||||
<%=intl._("Use non-SSL only")%></td></tr>
|
||||
<tr><td class="mediumtags" align="right"><b><%=intl._("Reseed URLs")%></b></td>
|
||||
<td><textarea name="reseedURL" wrap="off" spellcheck="false"><jsp:getProperty name="reseedHelper" property="reseedURL" /></textarea></td></tr>
|
||||
<tr><td class="mediumtags" align="right"><b><%=intl._("Enable HTTP proxy (not used for SSL)")%></b></td>
|
||||
<td><input type="checkbox" class="optbox" name="enable" value="true" <jsp:getProperty name="reseedHelper" property="enable" /> ></td></tr>
|
||||
<tr><td class="mediumtags" align="right"><b><%=intl._("HTTP Proxy Host")%>:</b></td>
|
||||
<td><input name="host" type="text" value="<jsp:getProperty name="reseedHelper" property="host" />" ></td></tr>
|
||||
<tr><td class="mediumtags" align="right"><b><%=intl._("HTTP Proxy Port")%>:</b></td>
|
||||
<td><input name="port" type="text" value="<jsp:getProperty name="reseedHelper" property="port" />" ></td></tr>
|
||||
</table></div>
|
||||
<hr><div class="formaction">
|
||||
<input type="submit" name="foo" value="<%=intl._("Cancel")%>" />
|
||||
<input type="submit" name="action" value="<%=intl._("Save changes and reseed now")%>" />
|
||||
<input type="submit" name="action" value="<%=intl._("Save changes")%>" />
|
||||
</div></form></div></div></body></html>
|
||||
@@ -50,9 +50,9 @@
|
||||
</tr><tr><td class= "mediumtags" align="right"><b><%=intl._("eepProxy port")%>:</b></td>
|
||||
<td><input type="text" size="4" name="proxyPort" value="<jsp:getProperty name="updatehelper" property="proxyPort" />" /></td>
|
||||
</tr><tr><td class= "mediumtags" align="right"><b><%=intl._("Update URLs")%>:</b></td>
|
||||
<td><textarea name="updateURL" wrap="off"><jsp:getProperty name="updatehelper" property="updateURL" /></textarea></td>
|
||||
<td><textarea name="updateURL" wrap="off" spellcheck="false"><jsp:getProperty name="updatehelper" property="updateURL" /></textarea></td>
|
||||
</tr><tr><td class= "mediumtags" align="right"><b><%=intl._("Trusted keys")%>:</b></td>
|
||||
<td><textarea name="trustedKeys" wrap="off"><jsp:getProperty name="updatehelper" property="trustedKeys" /></textarea></td>
|
||||
<td><textarea name="trustedKeys" wrap="off" spellcheck="false"><jsp:getProperty name="updatehelper" property="trustedKeys" /></textarea></td>
|
||||
</tr><tr><td class= "mediumtags" align="right"><b><%=intl._("Update with unsigned development builds?")%></b></td>
|
||||
<td><jsp:getProperty name="updatehelper" property="updateUnsigned" /></td>
|
||||
</tr><tr><td class= "mediumtags" align="right"><b><%=intl._("Unsigned Build URL")%>:</b></td>
|
||||
|
||||
63
apps/routerconsole/jsp/error500.jsp
Normal file
63
apps/routerconsole/jsp/error500.jsp
Normal file
@@ -0,0 +1,63 @@
|
||||
<%@page contentType="text/html"%>
|
||||
<%@page pageEncoding="UTF-8"%>
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<%
|
||||
// Let's make this easy...
|
||||
final Integer ERROR_CODE = (Integer) request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_STATUS_CODE);
|
||||
final String ERROR_URI = (String) request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_REQUEST_URI);
|
||||
final String ERROR_MESSAGE = (String) request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_MESSAGE);
|
||||
final Class ERROR_CLASS = (Class)request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_EXCEPTION_TYPE);
|
||||
final Throwable ERROR_THROWABLE = (Throwable)request.getAttribute(org.mortbay.jetty.servlet.ServletHandler.__J_S_ERROR_EXCEPTION);
|
||||
if (ERROR_CODE != null && ERROR_MESSAGE != null) {
|
||||
// this is deprecated but we don't want sendError()
|
||||
response.setStatus(ERROR_CODE.intValue(), ERROR_MESSAGE);
|
||||
}
|
||||
%>
|
||||
<html><head>
|
||||
<%@include file="css.jsi" %>
|
||||
<%=intl.title("Internal Error")%>
|
||||
</head><body>
|
||||
<div class="routersummaryouter">
|
||||
<div class="routersummary">
|
||||
<a href="/" title="<%=intl._("Router Console")%>"><img src="/themes/console/images/i2plogo.png" alt="<%=intl._("I2P Router Console")%>" border="0"></a><hr>
|
||||
<a href="/config"><%=intl._("Configuration")%></a> <a href="/help"><%=intl._("Help")%></a>
|
||||
</div></div>
|
||||
<h1><%=ERROR_CODE%> <%=ERROR_MESSAGE%></h1>
|
||||
<div class="sorry" id="warning">
|
||||
<%=intl._("Sorry! There has been an internal error.")%>
|
||||
<hr>
|
||||
<p>
|
||||
<% /* note to translators - both parameters are URLs */
|
||||
%><%=intl._("Please report bugs on {0} or {1}.",
|
||||
"<a href=\"http://trac.i2p2.i2p/newticket\">trac.i2p2.i2p</a>",
|
||||
"<a href=\"http://trac.i2p2.de/newticket\">trac.i2p2.de</a>")%>
|
||||
<%=intl._("You may use the username \"guest\" and password \"guest\" if you do not wish to register.")%>
|
||||
<p><%=intl._("Please include this information in bug reports")%>:
|
||||
</p></div><div class="sorry" id="warning2">
|
||||
<h3><%=intl._("Error Details")%></h3>
|
||||
<p>
|
||||
<%=intl._("Error {0}", ERROR_CODE)%>: <%=ERROR_URI%> <%=ERROR_MESSAGE%>
|
||||
</p><p>
|
||||
<%
|
||||
if (ERROR_THROWABLE != null) {
|
||||
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(2048);
|
||||
java.io.PrintStream ps = new java.io.PrintStream(baos);
|
||||
ERROR_THROWABLE.printStackTrace(ps);
|
||||
ps.close();
|
||||
String trace = baos.toString();
|
||||
trace = trace.replace("&", "&").replace("<", "<").replace(">", ">");
|
||||
trace = trace.replace("\n", "<br> \n");
|
||||
out.print(trace);
|
||||
}
|
||||
%>
|
||||
</p>
|
||||
<h3><%=intl._("I2P Version and Running Environment")%></h3>
|
||||
<p>
|
||||
<b>I2P version:</b> <%=net.i2p.router.RouterVersion.FULL_VERSION%><br>
|
||||
<b>Java version:</b> <%=System.getProperty("java.vendor")%> <%=System.getProperty("java.version")%> (<%=System.getProperty("java.runtime.name")%> <%=System.getProperty("java.runtime.version")%>)<br>
|
||||
<b>Platform:</b> <%=System.getProperty("os.name")%> <%=System.getProperty("os.arch")%> <%=System.getProperty("os.version")%><br>
|
||||
<b>Processor:</b> <%=net.i2p.util.NativeBigInteger.cpuModel()%> (<%=net.i2p.util.NativeBigInteger.cpuType()%>)<br>
|
||||
<b>Jbigi:</b> <%=net.i2p.util.NativeBigInteger.loadStatus()%><br>
|
||||
<b>Encoding:</b> <%=System.getProperty("file.encoding")%></p>
|
||||
<p><%=intl._("Note that system information, log timestamps, and log messages may provide clues to your location; please review everything you include in a bug report.")%></p>
|
||||
</div></body></html>
|
||||
@@ -15,11 +15,27 @@ boolean rendered = false;
|
||||
String c = request.getParameter("c");
|
||||
if (c != null && c.length() > 0) {
|
||||
java.io.OutputStream cout = response.getOutputStream();
|
||||
response.setContentType("image/png");
|
||||
response.setHeader("Cache-Control", "max-age=86400"); // cache for a day
|
||||
String base = net.i2p.I2PAppContext.getGlobalContext().getBaseDir().getAbsolutePath();
|
||||
String file = "docs" + java.io.File.separatorChar + "icons" + java.io.File.separatorChar +
|
||||
"flags" + java.io.File.separatorChar + c + ".png";
|
||||
java.io.File ffile = new java.io.File(base, file);
|
||||
long lastmod = ffile.lastModified();
|
||||
if (lastmod > 0) {
|
||||
long iflast = request.getDateHeader("If-Modified-Since");
|
||||
// iflast is -1 if not present; round down file time
|
||||
if (iflast >= ((lastmod / 1000) * 1000)) {
|
||||
response.sendError(304, "Not Modified");
|
||||
return;
|
||||
}
|
||||
response.setDateHeader("Last-Modified", lastmod);
|
||||
// cache for a day
|
||||
response.setDateHeader("Expires", net.i2p.I2PAppContext.getGlobalContext().clock().now() + 86400000l);
|
||||
response.setHeader("Cache-Control", "public, max-age=86400");
|
||||
}
|
||||
long length = ffile.length();
|
||||
if (length > 0)
|
||||
response.setHeader("Content-Length", Long.toString(length));
|
||||
response.setContentType("image/png");
|
||||
try {
|
||||
net.i2p.util.FileUtil.readFile(file, base, cout);
|
||||
rendered = true;
|
||||
|
||||
@@ -174,7 +174,7 @@ details on other applications available, as well as their licenses, please see t
|
||||
client applications can be found on our <a href="http://www.i2p2.i2p/download">download page</a>.
|
||||
.</p>
|
||||
|
||||
<h2>Release history</h2>
|
||||
<h2>Change Log</h2>
|
||||
<jsp:useBean class="net.i2p.router.web.ContentHelper" id="contenthelper" scope="request" />
|
||||
<% java.io.File fpath = new java.io.File(net.i2p.I2PAppContext.getGlobalContext().getBaseDir(), "history.txt"); %>
|
||||
<jsp:setProperty name="contenthelper" property="page" value="<%=fpath.getAbsolutePath()%>" />
|
||||
@@ -182,6 +182,5 @@ client applications can be found on our <a href="http://www.i2p2.i2p/download">d
|
||||
<jsp:setProperty name="contenthelper" property="startAtBeginning" value="true" />
|
||||
<jsp:getProperty name="contenthelper" property="textContent" />
|
||||
|
||||
<p>A more complete list of changes can be found
|
||||
in the history.txt file in your i2p directory.
|
||||
<p><a href="/history.txt">View the full change log</a>
|
||||
</p><hr></div></body></html>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<%@include file="summary.jsi" %>
|
||||
<h1><%=intl._("I2P Router Logs")%></h1>
|
||||
<div class="main" id="main">
|
||||
<div class="joblog"><h3><%=intl._("I2P Version & Running Environment")%></h3><a name="version"> </a>
|
||||
<div class="joblog"><h3><%=intl._("I2P Version and Running Environment")%></h3><a name="version"> </a>
|
||||
<p>
|
||||
<% /* note to translators - both parameters are URLs */
|
||||
%><%=intl._("Please report bugs on {0} or {1}.",
|
||||
|
||||
16
apps/routerconsole/jsp/viewhistory.jsp
Normal file
16
apps/routerconsole/jsp/viewhistory.jsp
Normal file
@@ -0,0 +1,16 @@
|
||||
<%
|
||||
/*
|
||||
* USE CAUTION WHEN EDITING
|
||||
* Trailing whitespace OR NEWLINE on the last line will cause
|
||||
* IllegalStateExceptions !!!
|
||||
*
|
||||
* Do not tag this file for translation.
|
||||
*/
|
||||
response.setContentType("text/plain");
|
||||
String base = net.i2p.I2PAppContext.getGlobalContext().getBaseDir().getAbsolutePath();
|
||||
try {
|
||||
net.i2p.util.FileUtil.readFile("history.txt", base, response.getOutputStream());
|
||||
} catch (java.io.IOException ioe) {
|
||||
response.sendError(403, ioe.toString());
|
||||
}
|
||||
%>
|
||||
@@ -19,7 +19,6 @@ if (uri.endsWith(".css")) {
|
||||
} else if (uri.endsWith(".ico")) {
|
||||
response.setContentType("image/x-icon");
|
||||
}
|
||||
response.setHeader("Cache-Control", "max-age=86400"); // cache for a day
|
||||
/*
|
||||
* User or plugin themes
|
||||
* If the request is for /themes/console/foo/bar/baz,
|
||||
@@ -44,5 +43,26 @@ if (themePath != null)
|
||||
else
|
||||
base = net.i2p.I2PAppContext.getGlobalContext().getBaseDir().getAbsolutePath() +
|
||||
java.io.File.separatorChar + "docs";
|
||||
net.i2p.util.FileUtil.readFile(uri, base, response.getOutputStream());
|
||||
java.io.File file = new java.io.File(base, uri);
|
||||
long lastmod = file.lastModified();
|
||||
if (lastmod > 0) {
|
||||
long iflast = request.getDateHeader("If-Modified-Since");
|
||||
// iflast is -1 if not present; round down file time
|
||||
if (iflast >= ((lastmod / 1000) * 1000)) {
|
||||
response.sendError(304, "Not Modified");
|
||||
return;
|
||||
}
|
||||
response.setDateHeader("Last-Modified", lastmod);
|
||||
// cache for a day
|
||||
response.setDateHeader("Expires", net.i2p.I2PAppContext.getGlobalContext().clock().now() + 86400000l);
|
||||
response.setHeader("Cache-Control", "public, max-age=86400");
|
||||
}
|
||||
long length = file.length();
|
||||
if (length > 0)
|
||||
response.setHeader("Content-Length", Long.toString(length));
|
||||
try {
|
||||
net.i2p.util.FileUtil.readFile(uri, base, response.getOutputStream());
|
||||
} catch (java.io.IOException ioe) {
|
||||
response.sendError(403, ioe.toString());
|
||||
}
|
||||
%>
|
||||
@@ -17,6 +17,11 @@
|
||||
<url-pattern>/javadoc/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>net.i2p.router.web.jsp.viewhistory_jsp</servlet-name>
|
||||
<url-pattern>/history.txt</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<session-config>
|
||||
<session-timeout>
|
||||
30
|
||||
@@ -30,4 +35,8 @@
|
||||
<error-code>404</error-code>
|
||||
<location>/error.jsp</location>
|
||||
</error-page>
|
||||
<error-page>
|
||||
<error-code>500</error-code>
|
||||
<location>/error500.jsp</location>
|
||||
</error-page>
|
||||
</web-app>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
5281
apps/routerconsole/locale/messages_es.po
Normal file
5281
apps/routerconsole/locale/messages_es.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -15,8 +15,9 @@ class I2PServerSocketFull implements I2PServerSocket {
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning, unlike regular ServerSocket, may return null
|
||||
*
|
||||
* @return I2PSocket
|
||||
* @return I2PSocket OR NULL
|
||||
* @throws net.i2p.I2PException
|
||||
* @throws SocketTimeoutException
|
||||
*/
|
||||
|
||||
@@ -114,7 +114,7 @@ public class I2PSocketManagerFull implements I2PSocketManager {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return connected I2PSocket
|
||||
* @return connected I2PSocket OR NULL
|
||||
* @throws net.i2p.I2PException
|
||||
* @throws java.net.SocketTimeoutException
|
||||
*/
|
||||
|
||||
@@ -497,7 +497,7 @@ class MessageOutputStream extends OutputStream {
|
||||
if (ws.writeFailed())
|
||||
throw new IOException("Flush available failed");
|
||||
else if (!ws.writeAccepted())
|
||||
throw new InterruptedIOException("Flush available timed out");
|
||||
throw new InterruptedIOException("Flush available timed out (" + _writeTimeout + "ms)");
|
||||
}
|
||||
long afterAccept = System.currentTimeMillis();
|
||||
if ( (afterAccept - afterBuild > 1000) && (_log.shouldLog(Log.DEBUG)) )
|
||||
|
||||
21
build.xml
21
build.xml
@@ -6,10 +6,8 @@
|
||||
<!--
|
||||
<property name="javac.compilerargs" value="-warn:-unchecked,raw,unused,serial" />
|
||||
-->
|
||||
<!-- Add Apache Harmony's Pack200 library if you don't have java.util.jar.Pack200
|
||||
See core/java/src/net/i2p/util/FileUtil.java for code changes required
|
||||
to use this library instead of Sun's version.
|
||||
Or to comment it all out if you don't have either.
|
||||
<!-- Additional classpath. No longer required; we find pack200 classes at runtime.
|
||||
See core/java/src/net/i2p/util/FileUtil.java for more info.
|
||||
-->
|
||||
<!--
|
||||
<property name="javac.classpath" value="/PATH/TO/pack200.jar" />
|
||||
@@ -239,7 +237,7 @@
|
||||
splitindex="true"
|
||||
doctitle="I2P Javadocs for Release ${release.number} Build ${build.number}"
|
||||
windowtitle="I2P Anonymous Network - Java Documentation - Version ${release.number}">
|
||||
<group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:freenet.support.CPUInformation:org.bouncycastle.crypto:org.bouncycastle.crypto.*:gnu.crypto.*:gnu.gettext:org.xlattice.crypto.filters:com.nettgryppa.security" />
|
||||
<group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:net.i2p.internal:net.i2p.internal.*:freenet.support.CPUInformation:org.bouncycastle.crypto:org.bouncycastle.crypto.*:gnu.crypto.*:gnu.gettext:org.xlattice.crypto.filters:com.nettgryppa.security" />
|
||||
<group title="Streaming Library" packages="net.i2p.client.streaming" />
|
||||
<group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:org.cybergarage.*:org.freenetproject" />
|
||||
<group title="Router Console" packages="net.i2p.router.web" />
|
||||
@@ -757,7 +755,7 @@
|
||||
</target>
|
||||
<target name="findbugs" depends="build2">
|
||||
<echo message="Starting findbugs, this will take a while..." />
|
||||
<exec executable="nice">
|
||||
<exec executable="nice" failonerror="true">
|
||||
<arg value="findbugs"/>
|
||||
<arg value="-textui"/>
|
||||
<arg value="-projectName"/>
|
||||
@@ -765,9 +763,9 @@
|
||||
<arg value="-sortByClass"/>
|
||||
<arg value="-xml"/>
|
||||
<arg value="-output"/>
|
||||
<arg value="findbugs.xml"/>
|
||||
<arg value="i2p.fba"/>
|
||||
<arg value="-auxclasspath"/>
|
||||
<arg value="build/commons-el.jar:build/commons-logging.jar:build/jasper-compiler.jar:build/jasper-runtime.jar:build/javax.servlet.jar:build/org.mortbay.jetty.jar:apps/jrobin/jrobin-1.4.0.jar:apps/systray/java/lib/systray4j.jar:installer/lib/wrapper/linux/wrapper.jar"/>
|
||||
<arg value="build/commons-el.jar:build/commons-logging.jar:build/jasper-compiler.jar:build/jasper-runtime.jar:build/javax.servlet.jar:build/org.mortbay.jetty.jar:apps/jrobin/jrobin-1.4.0.jar:apps/systray/java/lib/systray4j.jar:installer/lib/wrapper/linux/wrapper.jar:apps/susidns/src/WEB-INF/lib/standard.jar:apps/susidns/src/WEB-INF/lib/jstl.jar:apps/jrobin/jrobin-1.4.0.jar"/>
|
||||
<arg value="-sourcepath"/>
|
||||
<arg value="apps/BOB/src/:apps/addressbook/java/src/:apps/i2psnark/java/src/:apps/i2ptunnel/java/src/:apps/ministreaming/java/src/:apps/routerconsole/java/src/:apps/sam/java/src/:apps/streaming/java/src/:apps/susidns/src/java/src/:apps/susimail/src/src/:apps/systray/java/src/:core/java/src/:router/java/src/"/>
|
||||
<!-- start of the files to be analyzed -->
|
||||
@@ -781,15 +779,16 @@
|
||||
<arg value="build/jbigi.jar"/>
|
||||
<arg value="build/mstreaming.jar"/>
|
||||
<arg value="build/router.jar/"/>
|
||||
<!-- use the class files rather than the jar for routerconsole so we don't analyze jrobin -->
|
||||
<arg value="apps/routerconsole/java/build/obj/"/>
|
||||
<arg value="build/routerconsole.jar"/>
|
||||
<arg value="build/routerconsole.war"/>
|
||||
<arg value="build/sam.jar"/>
|
||||
<arg value="build/streaming.jar"/>
|
||||
<arg value="build/susidns.war"/>
|
||||
<arg value="build/susimail.war"/>
|
||||
<arg value="build/systray.jar"/>
|
||||
</exec>
|
||||
<echo message="Findbugs output stored in findbugs.xml" />
|
||||
<echo message="Findbugs output stored in i2p.fba" />
|
||||
<echo message="Now run: findbugs i2p.fba" />
|
||||
</target>
|
||||
<target name="buildWithDesktopgui" depends="buildrouter,builddepSmall">
|
||||
<ant dir="apps/desktopgui" target="build_jar" />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Created on Jul 14, 2004
|
||||
* Updated on Jan 8, 2011
|
||||
*/
|
||||
package freenet.support.CPUInformation;
|
||||
|
||||
@@ -129,11 +130,26 @@ public class CPUID {
|
||||
CPUIDResult c = doCPUID(1);
|
||||
return c.EAX & 0xf;
|
||||
}
|
||||
private static int getCPUFlags()
|
||||
private static int getEDXCPUFlags()
|
||||
{
|
||||
CPUIDResult c = doCPUID(1);
|
||||
return c.EDX;
|
||||
}
|
||||
private static int getECXCPUFlags()
|
||||
{
|
||||
CPUIDResult c = doCPUID(1);
|
||||
return c.ECX;
|
||||
}
|
||||
private static int getExtendedEDXCPUFlags()
|
||||
{
|
||||
CPUIDResult c = doCPUID(0x80000001);
|
||||
return c.EDX;
|
||||
}
|
||||
private static int getExtendedECXCPUFlags()
|
||||
{
|
||||
CPUIDResult c = doCPUID(0x80000001);
|
||||
return c.ECX;
|
||||
}
|
||||
|
||||
//Returns a CPUInfo item for the current type of CPU
|
||||
//If I could I would declare this method in a interface named
|
||||
@@ -163,13 +179,25 @@ public class CPUID {
|
||||
return getCPUVendorID();
|
||||
}
|
||||
public boolean hasMMX(){
|
||||
return (getCPUFlags() & 0x800000) >0; //Bit 23
|
||||
return (getEDXCPUFlags() & 0x800000) >0; //EDX Bit 23
|
||||
}
|
||||
public boolean hasSSE(){
|
||||
return (getCPUFlags() & 0x2000000) >0; //Bit 25
|
||||
return (getEDXCPUFlags() & 0x2000000) >0; //EDX Bit 25
|
||||
}
|
||||
public boolean hasSSE2(){
|
||||
return (getCPUFlags() & 0x4000000) >0; //Bit 26
|
||||
return (getEDXCPUFlags() & 0x4000000) >0; //EDX Bit 26
|
||||
}
|
||||
public boolean hasSSE3(){
|
||||
return (getEDXCPUFlags() & 0x1) >0; //ECX Bit 0
|
||||
}
|
||||
public boolean hasSSE41(){
|
||||
return (getEDXCPUFlags() & 0x80000) >0; //ECX Bit 19
|
||||
}
|
||||
public boolean hasSSE42(){
|
||||
return (getEDXCPUFlags() & 0x100000) >0; //ECX Bit 20
|
||||
}
|
||||
public boolean hasSSE4A(){
|
||||
return (getExtendedECXCPUFlags() & 0x40) >0; //Extended ECX Bit 6
|
||||
}
|
||||
public boolean IsC3Compatible() { return false; }
|
||||
}
|
||||
@@ -296,77 +324,119 @@ public class CPUID {
|
||||
return getCPUFamily() > 6 || (getCPUFamily() == 6 && getCPUModel() >=3);
|
||||
}
|
||||
public boolean IsPentium3Compatible()
|
||||
{
|
||||
return getCPUFamily() > 6 || (getCPUFamily() == 6 && getCPUModel() >=7);
|
||||
{
|
||||
// Atom
|
||||
if (getCPUExtendedModel() == 1 && (getCPUFamily() == 6 && (getCPUModel() == 12))){
|
||||
return true;
|
||||
// ??
|
||||
} else if (getCPUExtendedModel() == 0 && (getCPUFamily() > 6 || (getCPUFamily() == 6 && getCPUModel() >=7))){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean IsPentium4Compatible()
|
||||
{
|
||||
return getCPUFamily() >= 15;
|
||||
{
|
||||
// P4
|
||||
if (getCPUFamily() >= 15){
|
||||
return true;
|
||||
// Xeon MP (45nm) or Core i7
|
||||
} else if (getCPUExtendedModel() == 1 && (getCPUFamily() == 6 && (getCPUModel() == 10 || getCPUModel() == 13))){
|
||||
return true;
|
||||
// Core 2 Duo
|
||||
} else if (getCPUExtendedModel() == 0 && getCPUFamily() == 6 && getCPUModel() == 15){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public String getCPUModelString() throws UnknownCPUException {
|
||||
if(getCPUFamily() == 4){
|
||||
switch(getCPUModel()){
|
||||
case 0:
|
||||
return "486 DX-25/33";
|
||||
case 1:
|
||||
return "486 DX-50";
|
||||
case 2:
|
||||
return "486 SX";
|
||||
case 3:
|
||||
return "486 DX/2";
|
||||
case 4:
|
||||
return "486 SL";
|
||||
case 5:
|
||||
return "486 SX/2";
|
||||
case 7:
|
||||
return "486 DX/2-WB";
|
||||
case 8:
|
||||
return "486 DX/4";
|
||||
case 9:
|
||||
return "486 DX/4-WB";
|
||||
}
|
||||
}
|
||||
if(getCPUFamily() == 5){
|
||||
switch(getCPUModel()){
|
||||
case 0:
|
||||
return "Pentium 60/66 A-step";
|
||||
case 1:
|
||||
return "Pentium 60/66";
|
||||
case 2:
|
||||
return "Pentium 75 - 200";
|
||||
case 3:
|
||||
return "OverDrive PODP5V83";
|
||||
case 4:
|
||||
return "Pentium MMX";
|
||||
case 7:
|
||||
return "Mobile Pentium 75 - 200";
|
||||
case 8:
|
||||
return "Mobile Pentium MMX";
|
||||
}
|
||||
if (getCPUExtendedModel() == 0){
|
||||
if(getCPUFamily() == 4){
|
||||
switch(getCPUModel()){
|
||||
case 0:
|
||||
return "486 DX-25/33";
|
||||
case 1:
|
||||
return "486 DX-50";
|
||||
case 2:
|
||||
return "486 SX";
|
||||
case 3:
|
||||
return "486 DX/2";
|
||||
case 4:
|
||||
return "486 SL";
|
||||
case 5:
|
||||
return "486 SX/2";
|
||||
case 7:
|
||||
return "486 DX/2-WB";
|
||||
case 8:
|
||||
return "486 DX/4";
|
||||
case 9:
|
||||
return "486 DX/4-WB";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getCPUExtendedModel() == 0){
|
||||
if(getCPUFamily() == 5){
|
||||
switch(getCPUModel()){
|
||||
case 0:
|
||||
return "Pentium 60/66 A-step";
|
||||
case 1:
|
||||
return "Pentium 60/66";
|
||||
case 2:
|
||||
return "Pentium 75 - 200";
|
||||
case 3:
|
||||
return "OverDrive PODP5V83";
|
||||
case 4:
|
||||
return "Pentium MMX";
|
||||
case 7:
|
||||
return "Mobile Pentium 75 - 200";
|
||||
case 8:
|
||||
return "Mobile Pentium MMX";
|
||||
}
|
||||
}
|
||||
}
|
||||
if(getCPUFamily() == 6){
|
||||
switch(getCPUModel()){
|
||||
case 0:
|
||||
return "Pentium Pro A-step";
|
||||
case 1:
|
||||
return "Pentium Pro";
|
||||
case 3:
|
||||
return "Pentium II (Klamath)";
|
||||
case 5:
|
||||
return "Pentium II (Deschutes), Celeron (Covington), Mobile Pentium II (Dixon)";
|
||||
case 6:
|
||||
return "Mobile Pentium II, Celeron (Mendocino)";
|
||||
case 7:
|
||||
return "Pentium III (Katmai)";
|
||||
case 8:
|
||||
return "Pentium III (Coppermine), Celeron w/SSE";
|
||||
case 9:
|
||||
return "Mobile Pentium III";
|
||||
case 10:
|
||||
return "Pentium III Xeon (Cascades)";
|
||||
case 11:
|
||||
return "Pentium III (130 nm)";
|
||||
}
|
||||
if (getCPUExtendedModel() == 0){
|
||||
switch(getCPUModel()){
|
||||
case 0:
|
||||
return "Pentium Pro A-step";
|
||||
case 1:
|
||||
return "Pentium Pro";
|
||||
case 3:
|
||||
return "Pentium II (Klamath)";
|
||||
case 5:
|
||||
return "Pentium II (Deschutes), Celeron (Covington), Mobile Pentium II (Dixon)";
|
||||
case 6:
|
||||
return "Mobile Pentium II, Celeron (Mendocino)";
|
||||
case 7:
|
||||
return "Pentium III (Katmai)";
|
||||
case 8:
|
||||
return "Pentium III (Coppermine), Celeron w/SSE";
|
||||
case 9:
|
||||
return "Mobile Pentium III (Banias)";
|
||||
case 10:
|
||||
return "Pentium III Xeon (Cascades)";
|
||||
case 11:
|
||||
return "Pentium III (130 nm)";
|
||||
case 13:
|
||||
return "Mobile Pentium III (Dothan)";
|
||||
case 14:
|
||||
return "Mobile Core (Yonah)";
|
||||
case 15:
|
||||
return "Core 2 (Conroe)";
|
||||
}
|
||||
} else {
|
||||
if (getCPUExtendedModel() == 1){
|
||||
switch(getCPUModel()){
|
||||
case 10:
|
||||
return "Core i7";
|
||||
case 12:
|
||||
return "Atom";
|
||||
case 13:
|
||||
return "Xeon MP";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(getCPUFamily() == 7){
|
||||
switch(getCPUModel()){
|
||||
@@ -384,6 +454,10 @@ public class CPUID {
|
||||
return "Pentium IV (130 nm)";
|
||||
case 3:
|
||||
return "Pentium IV (90 nm)";
|
||||
case 4:
|
||||
return "Pentium IV (90 nm)";
|
||||
case 6:
|
||||
return "Pentium IV (65 nm)";
|
||||
}
|
||||
}
|
||||
if(getCPUExtendedFamily() == 1){
|
||||
@@ -407,7 +481,7 @@ public class CPUID {
|
||||
System.out.println("CPU Family: " + getCPUFamily());
|
||||
System.out.println("CPU Model: " + getCPUModel());
|
||||
System.out.println("CPU Stepping: " + getCPUStepping());
|
||||
System.out.println("CPU Flags: " + getCPUFlags());
|
||||
System.out.println("CPU Flags: " + getEDXCPUFlags());
|
||||
|
||||
CPUInfo c = getInfo();
|
||||
System.out.println(" **More CPUInfo**");
|
||||
@@ -415,6 +489,10 @@ public class CPUID {
|
||||
System.out.println(" CPU has MMX: " + c.hasMMX());
|
||||
System.out.println(" CPU has SSE: " + c.hasSSE());
|
||||
System.out.println(" CPU has SSE2: " + c.hasSSE2());
|
||||
System.out.println(" CPU has SSE3: " + c.hasSSE3());
|
||||
System.out.println(" CPU has SSE4.1: " + c.hasSSE41());
|
||||
System.out.println(" CPU has SSE4.2: " + c.hasSSE42());
|
||||
System.out.println(" CPU has SSE4A: " + c.hasSSE4A());
|
||||
if(c instanceof IntelCPUInfo){
|
||||
System.out.println(" **Intel-info**");
|
||||
System.out.println(" Is pII-compatible: "+((IntelCPUInfo)c).IsPentium2Compatible());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Created on Jul 16, 2004
|
||||
*
|
||||
* Created on Jul 14, 2004
|
||||
* Updated on Jan 8, 2011
|
||||
*/
|
||||
package freenet.support.CPUInformation;
|
||||
|
||||
@@ -42,5 +42,25 @@ public interface CPUInfo
|
||||
*/
|
||||
public boolean hasSSE2();
|
||||
|
||||
/**
|
||||
* @return true iff the CPU support the SSE3 instruction set.
|
||||
*/
|
||||
public boolean hasSSE3();
|
||||
|
||||
/**
|
||||
* @return true iff the CPU support the SSE4.1 instruction set.
|
||||
*/
|
||||
public boolean hasSSE41();
|
||||
|
||||
/**
|
||||
* @return true iff the CPU support the SSE4.2 instruction set.
|
||||
*/
|
||||
public boolean hasSSE42();
|
||||
|
||||
/**
|
||||
* @return true iff the CPU support the SSE4A instruction set.
|
||||
*/
|
||||
public boolean hasSSE4A();
|
||||
|
||||
public boolean IsC3Compatible();
|
||||
}
|
||||
|
||||
@@ -168,6 +168,7 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
|
||||
//System.out.println("Refilling " + (++refillCount) + " after " + diff + " for the PRNG took " + refillTime);
|
||||
}
|
||||
|
||||
/*****
|
||||
public static void main(String args[]) {
|
||||
try {
|
||||
AsyncFortunaStandalone rand = new AsyncFortunaStandalone(null); // Will cause NPEs above; fix this if you want to test! Sorry...
|
||||
@@ -195,4 +196,5 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
try { Thread.sleep(5*60*1000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
*****/
|
||||
}
|
||||
|
||||
@@ -351,6 +351,7 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl
|
||||
}
|
||||
}
|
||||
|
||||
/*****
|
||||
public static void main(String args[]) {
|
||||
byte in[] = new byte[16];
|
||||
byte out[] = new byte[16];
|
||||
@@ -379,7 +380,7 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl
|
||||
long after = System.currentTimeMillis();
|
||||
System.out.println("encrypting 4MB took " + (after-beforeAll));
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
/*
|
||||
****/ /*
|
||||
FortunaStandalone f = new FortunaStandalone();
|
||||
java.util.HashMap props = new java.util.HashMap();
|
||||
byte initSeed[] = new byte[1234];
|
||||
@@ -394,5 +395,7 @@ public class FortunaStandalone extends BasePRNGStandalone implements Serializabl
|
||||
long time = System.currentTimeMillis() - before;
|
||||
System.out.println("512MB took " + time + ", or " + (8*64d)/((double)time/1000d) +"MBps");
|
||||
*/
|
||||
/*****
|
||||
}
|
||||
*****/
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ package net.i2p;
|
||||
public class CoreVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
public final static String VERSION = "0.8.2";
|
||||
public final static String VERSION = "0.8.3";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Core version: " + VERSION);
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.i2p;
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.client.naming.NamingService;
|
||||
@@ -21,7 +22,9 @@ import net.i2p.crypto.KeyGenerator;
|
||||
import net.i2p.crypto.SHA256Generator;
|
||||
import net.i2p.crypto.SessionKeyManager;
|
||||
import net.i2p.crypto.TransientSessionKeyManager;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.RoutingKeyGenerator;
|
||||
import net.i2p.internal.InternalClientManager;
|
||||
import net.i2p.stat.StatManager;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
@@ -363,10 +366,12 @@ public class I2PAppContext {
|
||||
if (_tmpDir == null) {
|
||||
String d = getProperty("i2p.dir.temp", System.getProperty("java.io.tmpdir"));
|
||||
// our random() probably isn't warmed up yet
|
||||
String f = "i2p-" + Math.abs((new java.util.Random()).nextInt()) + ".tmp";
|
||||
byte[] rand = new byte[6];
|
||||
(new Random()).nextBytes(rand);
|
||||
String f = "i2p-" + Base64.encode(rand) + ".tmp";
|
||||
_tmpDir = new SecureDirectory(d, f);
|
||||
if (_tmpDir.exists()) {
|
||||
// good or bad ?
|
||||
// good or bad ? loop and try again?
|
||||
} else if (_tmpDir.mkdir()) {
|
||||
_tmpDir.deleteOnExit();
|
||||
} else {
|
||||
@@ -843,4 +848,13 @@ public class I2PAppContext {
|
||||
public boolean isRouterContext() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to connect to the router in the same JVM.
|
||||
* @return always null in I2PAppContext, the client manager if in RouterContext
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public InternalClientManager internalClientManager() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,6 @@ class BWLimitsMessageHandler extends HandlerImpl {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handle message " + message);
|
||||
BandwidthLimitsMessage msg = (BandwidthLimitsMessage) message;
|
||||
((I2PSimpleSession)session).bwReceived(msg.getLimits());
|
||||
session.bwReceived(msg.getLimits());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
import net.i2p.data.i2cp.I2CPMessage;
|
||||
import net.i2p.data.i2cp.I2CPMessageImpl;
|
||||
import net.i2p.data.i2cp.I2CPMessageException;
|
||||
import net.i2p.internal.PoisonI2CPMessage;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
|
||||
/**
|
||||
@@ -50,7 +51,7 @@ class ClientWriterRunner implements Runnable {
|
||||
public void stopWriting() {
|
||||
_messagesToWrite.clear();
|
||||
try {
|
||||
_messagesToWrite.put(new PoisonMessage());
|
||||
_messagesToWrite.put(new PoisonI2CPMessage());
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
|
||||
@@ -62,7 +63,7 @@ class ClientWriterRunner implements Runnable {
|
||||
} catch (InterruptedException ie) {
|
||||
continue;
|
||||
}
|
||||
if (msg.getType() == PoisonMessage.MESSAGE_TYPE)
|
||||
if (msg.getType() == PoisonI2CPMessage.MESSAGE_TYPE)
|
||||
break;
|
||||
// only thread, we don't need synchronized
|
||||
try {
|
||||
@@ -80,18 +81,4 @@ class ClientWriterRunner implements Runnable {
|
||||
}
|
||||
_messagesToWrite.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* End-of-stream msg used to stop the concurrent queue
|
||||
* See http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html
|
||||
*
|
||||
*/
|
||||
private static class PoisonMessage extends I2CPMessageImpl {
|
||||
public static final int MESSAGE_TYPE = 999999;
|
||||
public int getType() {
|
||||
return MESSAGE_TYPE;
|
||||
}
|
||||
public void doReadMessage(InputStream buf, int size) throws I2CPMessageException, IOException {}
|
||||
public byte[] doWriteMessage() throws I2CPMessageException, IOException { return null; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ import net.i2p.data.i2cp.I2CPMessage;
|
||||
import net.i2p.data.i2cp.DestReplyMessage;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
|
||||
/**
|
||||
* Handle I2CP dest replies from the router
|
||||
*/
|
||||
@@ -22,6 +25,14 @@ class DestReplyMessageHandler extends HandlerImpl {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handle message " + message);
|
||||
DestReplyMessage msg = (DestReplyMessage) message;
|
||||
((I2PSimpleSession)session).destReceived(msg.getDestination());
|
||||
Destination d = msg.getDestination();
|
||||
if (d != null) {
|
||||
session.destReceived(d);
|
||||
} else {
|
||||
Hash h = msg.getHash();
|
||||
if (h != null)
|
||||
session.destLookupFailed(h);
|
||||
}
|
||||
// else let it time out
|
||||
}
|
||||
}
|
||||
|
||||
183
core/java/src/net/i2p/client/I2CPSSLSocketFactory.java
Normal file
183
core/java/src/net/i2p/client/I2CPSSLSocketFactory.java
Normal file
@@ -0,0 +1,183 @@
|
||||
package net.i2p.client;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
import java.security.KeyStore;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateExpiredException;
|
||||
import java.security.cert.CertificateNotYetValidException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Loads trusted ASCII certs from ~/.i2p/certificates/ and $CWD/certificates/.
|
||||
* Keeps a single static SSLContext for the whole JVM.
|
||||
*
|
||||
* @author zzz
|
||||
* @since 0.8.3
|
||||
*/
|
||||
class I2CPSSLSocketFactory {
|
||||
|
||||
private static final Object _initLock = new Object();
|
||||
private static SSLSocketFactory _factory;
|
||||
private static Log _log;
|
||||
|
||||
private static final String CERT_DIR = "certificates";
|
||||
|
||||
/**
|
||||
* Initializes the static SSL Context if required, then returns a socket
|
||||
* to the host.
|
||||
*
|
||||
* @param ctx just for logging
|
||||
* @throws IOException on init error or usual socket errors
|
||||
*/
|
||||
public static Socket createSocket(I2PAppContext ctx, String host, int port) throws IOException {
|
||||
synchronized(_initLock) {
|
||||
if (_factory == null) {
|
||||
_log = ctx.logManager().getLog(I2CPSSLSocketFactory.class);
|
||||
initSSLContext(ctx);
|
||||
if (_factory == null)
|
||||
throw new IOException("Unable to create SSL Context for I2CP Client");
|
||||
_log.info("I2CP Client-side SSL Context initialized");
|
||||
}
|
||||
}
|
||||
return _factory.createSocket(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads certs from
|
||||
* the ~/.i2p/certificates/ and $CWD/certificates/ directories.
|
||||
*/
|
||||
private static void initSSLContext(I2PAppContext context) {
|
||||
KeyStore ks;
|
||||
try {
|
||||
ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
ks.load(null, "".toCharArray());
|
||||
} catch (GeneralSecurityException gse) {
|
||||
_log.error("Key Store init error", gse);
|
||||
return;
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Key Store init error", ioe);
|
||||
return;
|
||||
}
|
||||
|
||||
File dir = new File(context.getConfigDir(), CERT_DIR);
|
||||
int adds = addCerts(dir, ks);
|
||||
int totalAdds = adds;
|
||||
if (adds > 0 && _log.shouldLog(Log.INFO))
|
||||
_log.info("Loaded " + adds + " trusted certificates from " + dir.getAbsolutePath());
|
||||
|
||||
File dir2 = new File(System.getProperty("user.dir"), CERT_DIR);
|
||||
if (!dir.getAbsolutePath().equals(dir2.getAbsolutePath())) {
|
||||
adds = addCerts(dir2, ks);
|
||||
totalAdds += adds;
|
||||
if (adds > 0 && _log.shouldLog(Log.INFO))
|
||||
_log.info("Loaded " + adds + " trusted certificates from " + dir.getAbsolutePath());
|
||||
}
|
||||
if (totalAdds > 0) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Loaded total of " + totalAdds + " new trusted certificates");
|
||||
} else {
|
||||
_log.error("No trusted certificates loaded (looked in " +
|
||||
dir.getAbsolutePath() + (dir.getAbsolutePath().equals(dir2.getAbsolutePath()) ? "" : (" and " + dir2.getAbsolutePath())) +
|
||||
", I2CP SSL client connections will fail. " +
|
||||
"Copy the file certificates/i2cp.local.crt from the router to the directory.");
|
||||
// don't continue, since we didn't load the system keystore, we have nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
SSLContext sslc = SSLContext.getInstance("TLS");
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(ks);
|
||||
sslc.init(null, tmf.getTrustManagers(), context.random());
|
||||
_factory = sslc.getSocketFactory();
|
||||
} catch (GeneralSecurityException gse) {
|
||||
_log.error("SSL context init error", gse);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all X509 Certs from a directory and add them to the
|
||||
* trusted set of certificates in the key store
|
||||
*
|
||||
* @return number successfully added
|
||||
*/
|
||||
private static int addCerts(File dir, KeyStore ks) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Looking for X509 Certificates in " + dir.getAbsolutePath());
|
||||
int added = 0;
|
||||
if (dir.exists() && dir.isDirectory()) {
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null) {
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File f = files[i];
|
||||
if (!f.isFile())
|
||||
continue;
|
||||
// use file name as alias
|
||||
String alias = f.getName().toLowerCase();
|
||||
boolean success = addCert(f, alias, ks);
|
||||
if (success)
|
||||
added++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return added;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an X509 Cert from a file and add it to the
|
||||
* trusted set of certificates in the key store
|
||||
*
|
||||
* @return success
|
||||
*/
|
||||
private static boolean addCert(File file, String alias, KeyStore ks) {
|
||||
InputStream fis = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
X509Certificate cert = (X509Certificate)cf.generateCertificate(fis);
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Read X509 Certificate from " + file.getAbsolutePath() +
|
||||
" Issuer: " + cert.getIssuerX500Principal() +
|
||||
"; Valid From: " + cert.getNotBefore() +
|
||||
" To: " + cert.getNotAfter());
|
||||
}
|
||||
try {
|
||||
cert.checkValidity();
|
||||
} catch (CertificateExpiredException cee) {
|
||||
_log.error("Rejecting expired X509 Certificate: " + file.getAbsolutePath(), cee);
|
||||
return false;
|
||||
} catch (CertificateNotYetValidException cnyve) {
|
||||
_log.error("Rejecting X509 Certificate not yet valid: " + file.getAbsolutePath(), cnyve);
|
||||
return false;
|
||||
}
|
||||
ks.setCertificateEntry(alias, cert);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Now trusting X509 Certificate, Issuer: " + cert.getIssuerX500Principal());
|
||||
} catch (GeneralSecurityException gse) {
|
||||
_log.error("Error reading X509 Certificate: " + file.getAbsolutePath(), gse);
|
||||
return false;
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error reading X509 Certificate: " + file.getAbsolutePath(), ioe);
|
||||
return false;
|
||||
} finally {
|
||||
try { if (fis != null) fis.close(); } catch (IOException foo) {}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ package net.i2p.client;
|
||||
*/
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.i2cp.BandwidthLimitsMessage;
|
||||
import net.i2p.data.i2cp.DestReplyMessage;
|
||||
import net.i2p.data.i2cp.DisconnectMessage;
|
||||
import net.i2p.data.i2cp.MessagePayloadMessage;
|
||||
import net.i2p.data.i2cp.MessageStatusMessage;
|
||||
@@ -36,6 +38,8 @@ class I2PClientMessageHandlerMap {
|
||||
highest = Math.max(highest, MessagePayloadMessage.MESSAGE_TYPE);
|
||||
highest = Math.max(highest, MessageStatusMessage.MESSAGE_TYPE);
|
||||
highest = Math.max(highest, SetDateMessage.MESSAGE_TYPE);
|
||||
highest = Math.max(highest, DestReplyMessage.MESSAGE_TYPE);
|
||||
highest = Math.max(highest, BandwidthLimitsMessage.MESSAGE_TYPE);
|
||||
|
||||
_handlers = new I2CPMessageHandler[highest+1];
|
||||
_handlers[DisconnectMessage.MESSAGE_TYPE] = new DisconnectMessageHandler(context);
|
||||
@@ -44,6 +48,8 @@ class I2PClientMessageHandlerMap {
|
||||
_handlers[MessagePayloadMessage.MESSAGE_TYPE] = new MessagePayloadMessageHandler(context);
|
||||
_handlers[MessageStatusMessage.MESSAGE_TYPE] = new MessageStatusMessageHandler(context);
|
||||
_handlers[SetDateMessage.MESSAGE_TYPE] = new SetDateMessageHandler(context);
|
||||
_handlers[DestReplyMessage.MESSAGE_TYPE] = new DestReplyMessageHandler(context);
|
||||
_handlers[BandwidthLimitsMessage.MESSAGE_TYPE] = new BWLimitsMessageHandler(context);
|
||||
}
|
||||
|
||||
public I2CPMessageHandler getHandler(int messageTypeId) {
|
||||
|
||||
@@ -138,13 +138,21 @@ public interface I2PSession {
|
||||
public SigningPrivateKey getPrivateKey();
|
||||
|
||||
/**
|
||||
* Lookup up a Hash
|
||||
*
|
||||
* Lookup a Destination by Hash.
|
||||
* Blocking. Waits a max of 10 seconds by default.
|
||||
*/
|
||||
public Destination lookupDest(Hash h) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* Get the current bandwidth limits
|
||||
* Blocking.
|
||||
* @param maxWait ms
|
||||
* @since 0.8.3
|
||||
* @return null on failure
|
||||
*/
|
||||
public Destination lookupDest(Hash h, long maxWait) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* Get the current bandwidth limits. Blocking.
|
||||
*/
|
||||
public int[] bandwidthLimits() throws I2PSessionException;
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -23,6 +22,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataFormatException;
|
||||
@@ -33,14 +34,18 @@ import net.i2p.data.PrivateKey;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.data.SessionTag;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.i2cp.DestLookupMessage;
|
||||
import net.i2p.data.i2cp.GetBandwidthLimitsMessage;
|
||||
import net.i2p.data.i2cp.GetDateMessage;
|
||||
import net.i2p.data.i2cp.I2CPMessage;
|
||||
import net.i2p.data.i2cp.I2CPMessageException;
|
||||
import net.i2p.data.i2cp.I2CPMessageReader;
|
||||
import net.i2p.data.i2cp.MessagePayloadMessage;
|
||||
import net.i2p.data.i2cp.SessionId;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.InternalSocket;
|
||||
import net.i2p.internal.I2CPMessageQueue;
|
||||
import net.i2p.internal.InternalClientManager;
|
||||
import net.i2p.internal.QueuedI2CPMessageReader;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
@@ -66,9 +71,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
/** currently granted lease set, or null */
|
||||
private LeaseSet _leaseSet;
|
||||
|
||||
/** hostname of router */
|
||||
/** hostname of router - will be null if in RouterContext */
|
||||
protected String _hostname;
|
||||
/** port num to router */
|
||||
/** port num to router - will be 0 if in RouterContext */
|
||||
protected int _portNum;
|
||||
/** socket for comm */
|
||||
protected Socket _socket;
|
||||
@@ -79,6 +84,13 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
/** where we pipe our messages */
|
||||
protected /* FIXME final FIXME */OutputStream _out;
|
||||
|
||||
/**
|
||||
* Used for internal connections to the router.
|
||||
* If this is set, _socket, _writer, and _out will be null.
|
||||
* @since 0.8.3
|
||||
*/
|
||||
protected I2CPMessageQueue _queue;
|
||||
|
||||
/** who we send events to */
|
||||
protected I2PSessionListener _sessionListener;
|
||||
|
||||
@@ -86,6 +98,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
protected I2CPMessageProducer _producer;
|
||||
/** map of Long --> MessagePayloadMessage */
|
||||
protected Map<Long, MessagePayloadMessage> _availableMessages;
|
||||
|
||||
/** hashes of lookups we are waiting for */
|
||||
protected final LinkedBlockingQueue<LookupWaiter> _pendingLookups = new LinkedBlockingQueue();
|
||||
protected final Object _bwReceivedLock = new Object();
|
||||
protected int[] _bwLimits;
|
||||
|
||||
protected I2PClientMessageHandlerMap _handlerMap;
|
||||
|
||||
@@ -122,6 +139,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
private long _lastActivity;
|
||||
private boolean _isReduced;
|
||||
|
||||
/** SSL interface (only) @since 0.8.3 */
|
||||
protected static final String PROP_ENABLE_SSL = "i2cp.SSL";
|
||||
|
||||
void dateUpdated() {
|
||||
_dateReceived = true;
|
||||
synchronized (_dateReceivedLock) {
|
||||
@@ -172,19 +192,24 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
protected void loadConfig(Properties options) {
|
||||
_options = new Properties();
|
||||
_options.putAll(filter(options));
|
||||
_hostname = _options.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
|
||||
String portNum = _options.getProperty(I2PClient.PROP_TCP_PORT, LISTEN_PORT + "");
|
||||
try {
|
||||
_portNum = Integer.parseInt(portNum);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + "Invalid port number specified, defaulting to "
|
||||
+ LISTEN_PORT, nfe);
|
||||
_portNum = LISTEN_PORT;
|
||||
if (_context.isRouterContext()) {
|
||||
// just for logging
|
||||
_hostname = "[internal connection]";
|
||||
} else {
|
||||
_hostname = _options.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
|
||||
String portNum = _options.getProperty(I2PClient.PROP_TCP_PORT, LISTEN_PORT + "");
|
||||
try {
|
||||
_portNum = Integer.parseInt(portNum);
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + "Invalid port number specified, defaulting to "
|
||||
+ LISTEN_PORT, nfe);
|
||||
_portNum = LISTEN_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
// auto-add auth if required, not set in the options, and we are in the same JVM
|
||||
if (_context.isRouterContext() &&
|
||||
// auto-add auth if required, not set in the options, and we are not in the same JVM
|
||||
if ((!_context.isRouterContext()) &&
|
||||
Boolean.valueOf(_context.getProperty("i2cp.auth")).booleanValue() &&
|
||||
((!options.containsKey("i2cp.username")) || (!options.containsKey("i2cp.password")))) {
|
||||
String configUser = _context.getProperty("i2cp.username");
|
||||
@@ -272,10 +297,6 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
setOpening(true);
|
||||
_closed = false;
|
||||
_availabilityNotifier.stopNotifying();
|
||||
I2PThread notifier = new I2PThread(_availabilityNotifier);
|
||||
notifier.setName("Notifier " + _myDestination.calculateHash().toBase64().substring(0,4));
|
||||
notifier.setDaemon(true);
|
||||
notifier.start();
|
||||
|
||||
if ( (_options != null) &&
|
||||
(I2PClient.PROP_RELIABILITY_GUARANTEED.equals(_options.getProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT))) ) {
|
||||
@@ -285,17 +306,32 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
|
||||
long startConnect = _context.clock().now();
|
||||
try {
|
||||
// If we are in the router JVM, connect using the interal pseudo-socket
|
||||
_socket = InternalSocket.getSocket(_hostname, _portNum);
|
||||
// _socket.setSoTimeout(1000000); // Uhmmm we could really-really use a real timeout, and handle it.
|
||||
_out = _socket.getOutputStream();
|
||||
synchronized (_out) {
|
||||
_out.write(I2PClient.PROTOCOL_BYTE);
|
||||
_out.flush();
|
||||
// If we are in the router JVM, connect using the interal queue
|
||||
if (_context.isRouterContext()) {
|
||||
// _socket, _out, and _writer remain null
|
||||
InternalClientManager mgr = _context.internalClientManager();
|
||||
if (mgr == null)
|
||||
throw new I2PSessionException("Router is not ready for connections");
|
||||
// the following may throw an I2PSessionException
|
||||
_queue = mgr.connect();
|
||||
_reader = new QueuedI2CPMessageReader(_queue, this);
|
||||
} else {
|
||||
if (Boolean.valueOf(_options.getProperty(PROP_ENABLE_SSL)).booleanValue())
|
||||
_socket = I2CPSSLSocketFactory.createSocket(_context, _hostname, _portNum);
|
||||
else
|
||||
_socket = new Socket(_hostname, _portNum);
|
||||
// _socket.setSoTimeout(1000000); // Uhmmm we could really-really use a real timeout, and handle it.
|
||||
_out = _socket.getOutputStream();
|
||||
synchronized (_out) {
|
||||
_out.write(I2PClient.PROTOCOL_BYTE);
|
||||
_out.flush();
|
||||
}
|
||||
_writer = new ClientWriterRunner(_out, this);
|
||||
InputStream in = _socket.getInputStream();
|
||||
_reader = new I2CPMessageReader(in, this);
|
||||
}
|
||||
_writer = new ClientWriterRunner(_out, this);
|
||||
InputStream in = _socket.getInputStream();
|
||||
_reader = new I2CPMessageReader(in, this);
|
||||
Thread notifier = new I2PAppThread(_availabilityNotifier, "ClientNotifier " + getPrefix(), true);
|
||||
notifier.start();
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "before startReading");
|
||||
_reader.startReading();
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Before getDate");
|
||||
@@ -435,6 +471,10 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This notifies the client of payload messages.
|
||||
* Needs work.
|
||||
*/
|
||||
protected class AvailabilityNotifier implements Runnable {
|
||||
private List _pendingIds;
|
||||
private List _pendingSizes;
|
||||
@@ -497,8 +537,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
}
|
||||
|
||||
/**
|
||||
* Recieve notification of some I2CP message and handle it if possible
|
||||
*
|
||||
* The I2CPMessageEventListener callback.
|
||||
* Recieve notification of some I2CP message and handle it if possible.
|
||||
* @param reader unused
|
||||
*/
|
||||
public void messageReceived(I2CPMessageReader reader, I2CPMessage message) {
|
||||
I2CPMessageHandler handler = _handlerMap.getHandler(message.getType());
|
||||
@@ -515,7 +556,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
}
|
||||
|
||||
/**
|
||||
* Recieve notifiation of an error reading the I2CP stream
|
||||
* The I2CPMessageEventListener callback.
|
||||
* Recieve notifiation of an error reading the I2CP stream.
|
||||
* @param reader unused
|
||||
* @param error non-null
|
||||
*/
|
||||
public void readError(I2CPMessageReader reader, Exception error) {
|
||||
@@ -567,9 +610,14 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
* @throws I2PSessionException if the message is malformed or there is an error writing it out
|
||||
*/
|
||||
void sendMessage(I2CPMessage message) throws I2PSessionException {
|
||||
if (isClosed() || _writer == null)
|
||||
if (isClosed())
|
||||
throw new I2PSessionException("Already closed");
|
||||
_writer.addMessage(message);
|
||||
else if (_queue != null)
|
||||
_queue.offer(message); // internal
|
||||
else if (_writer == null)
|
||||
throw new I2PSessionException("Already closed");
|
||||
else
|
||||
_writer.addMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -581,8 +629,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
// Only log as WARN if the router went away
|
||||
int level;
|
||||
String msgpfx;
|
||||
if ((error instanceof EOFException) ||
|
||||
(error.getMessage() != null && error.getMessage().startsWith("Pipe closed"))) {
|
||||
if (error instanceof EOFException) {
|
||||
level = Log.WARN;
|
||||
msgpfx = "Router closed connection: ";
|
||||
} else {
|
||||
@@ -631,7 +678,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
_log.warn("Error destroying the session", ipe);
|
||||
}
|
||||
}
|
||||
_availabilityNotifier.stopNotifying();
|
||||
// SimpleSession does not initialize
|
||||
if (_availabilityNotifier != null)
|
||||
_availabilityNotifier.stopNotifying();
|
||||
_closed = true;
|
||||
_closing = false;
|
||||
closeSocket();
|
||||
@@ -649,6 +698,10 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
_reader.stopReading();
|
||||
_reader = null;
|
||||
}
|
||||
if (_queue != null) {
|
||||
// internal
|
||||
_queue.close();
|
||||
}
|
||||
if (_writer != null) {
|
||||
_writer.stopWriting();
|
||||
_writer = null;
|
||||
@@ -666,7 +719,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
}
|
||||
|
||||
/**
|
||||
* Recieve notification that the I2CP connection was disconnected
|
||||
* The I2CPMessageEventListener callback.
|
||||
* Recieve notification that the I2CP connection was disconnected.
|
||||
* @param reader unused
|
||||
*/
|
||||
public void disconnected(I2CPMessageReader reader) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Disconnected", new Exception("Disconnected"));
|
||||
@@ -733,21 +788,113 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
buf.append(s);
|
||||
else
|
||||
buf.append(getClass().getSimpleName());
|
||||
buf.append(" #");
|
||||
if (_sessionId != null)
|
||||
buf.append(_sessionId.getSessionId());
|
||||
else
|
||||
buf.append("n/a");
|
||||
buf.append(" #").append(_sessionId.getSessionId());
|
||||
buf.append("]: ");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public Destination lookupDest(Hash h) throws I2PSessionException {
|
||||
return null;
|
||||
/** called by the message handler */
|
||||
void destReceived(Destination d) {
|
||||
Hash h = d.calculateHash();
|
||||
for (LookupWaiter w : _pendingLookups) {
|
||||
if (w.hash.equals(h)) {
|
||||
w.destination = d;
|
||||
synchronized (w) {
|
||||
w.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** called by the message handler */
|
||||
void destLookupFailed(Hash h) {
|
||||
for (LookupWaiter w : _pendingLookups) {
|
||||
if (w.hash.equals(h)) {
|
||||
synchronized (w) {
|
||||
w.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** called by the message handler */
|
||||
void bwReceived(int[] i) {
|
||||
_bwLimits = i;
|
||||
synchronized (_bwReceivedLock) {
|
||||
_bwReceivedLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple object to wait for lookup replies
|
||||
* @since 0.8.3
|
||||
*/
|
||||
private static class LookupWaiter {
|
||||
/** the request */
|
||||
public final Hash hash;
|
||||
/** the reply */
|
||||
public Destination destination;
|
||||
|
||||
public LookupWaiter(Hash h) {
|
||||
this.hash = h;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking. Waits a max of 10 seconds by default.
|
||||
* See lookupDest with maxWait parameter to change.
|
||||
* Implemented in 0.8.3 in I2PSessionImpl;
|
||||
* previously was available only in I2PSimpleSession.
|
||||
* Multiple outstanding lookups are now allowed.
|
||||
* @return null on failure
|
||||
*/
|
||||
public Destination lookupDest(Hash h) throws I2PSessionException {
|
||||
return lookupDest(h, 10*1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking.
|
||||
* @param maxWait ms
|
||||
* @since 0.8.3
|
||||
* @return null on failure
|
||||
*/
|
||||
public Destination lookupDest(Hash h, long maxWait) throws I2PSessionException {
|
||||
if (_closed)
|
||||
return null;
|
||||
LookupWaiter waiter = new LookupWaiter(h);
|
||||
_pendingLookups.offer(waiter);
|
||||
try {
|
||||
sendMessage(new DestLookupMessage(h));
|
||||
try {
|
||||
synchronized (waiter) {
|
||||
waiter.wait(maxWait);
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
} finally {
|
||||
_pendingLookups.remove(waiter);
|
||||
}
|
||||
return waiter.destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking. Waits a max of 5 seconds.
|
||||
* But shouldn't take long.
|
||||
* Implemented in 0.8.3 in I2PSessionImpl;
|
||||
* previously was available only in I2PSimpleSession.
|
||||
* Multiple outstanding lookups are now allowed.
|
||||
* @return null on failure
|
||||
*/
|
||||
public int[] bandwidthLimits() throws I2PSessionException {
|
||||
return null;
|
||||
if (_closed)
|
||||
return null;
|
||||
sendMessage(new GetBandwidthLimitsMessage());
|
||||
try {
|
||||
synchronized (_bwReceivedLock) {
|
||||
_bwReceivedLock.wait(5*1000);
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
return _bwLimits;
|
||||
}
|
||||
|
||||
protected void updateActivity() {
|
||||
|
||||
@@ -274,7 +274,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession {
|
||||
_demultiplexer.messageAvailable(I2PSessionMuxedImpl.this,
|
||||
msg.id, msg.size, msg.proto, msg.fromPort, msg.toPort);
|
||||
} catch (Exception e) {
|
||||
_log.error("Error notifying app of message availability");
|
||||
_log.error("Error notifying app of message availability", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@ import net.i2p.data.i2cp.DestLookupMessage;
|
||||
import net.i2p.data.i2cp.DestReplyMessage;
|
||||
import net.i2p.data.i2cp.GetBandwidthLimitsMessage;
|
||||
import net.i2p.data.i2cp.I2CPMessageReader;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.InternalSocket;
|
||||
import net.i2p.internal.I2CPMessageQueue;
|
||||
import net.i2p.internal.InternalClientManager;
|
||||
import net.i2p.internal.QueuedI2CPMessageReader;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
|
||||
/**
|
||||
* Create a new session for doing naming and bandwidth queries only. Do not create a Destination.
|
||||
@@ -31,12 +33,6 @@ import net.i2p.util.InternalSocket;
|
||||
* @author zzz
|
||||
*/
|
||||
class I2PSimpleSession extends I2PSessionImpl2 {
|
||||
private boolean _destReceived;
|
||||
private /* FIXME final FIXME */ Object _destReceivedLock;
|
||||
private Destination _destination;
|
||||
private boolean _bwReceived;
|
||||
private /* FIXME final FIXME */ Object _bwReceivedLock;
|
||||
private int[] _bwLimits;
|
||||
|
||||
/**
|
||||
* Create a new session for doing naming and bandwidth queries only. Do not create a destination.
|
||||
@@ -44,12 +40,12 @@ class I2PSimpleSession extends I2PSessionImpl2 {
|
||||
* @throws I2PSessionException if there is a problem
|
||||
*/
|
||||
public I2PSimpleSession(I2PAppContext context, Properties options) throws I2PSessionException {
|
||||
// Warning, does not call super()
|
||||
_context = context;
|
||||
_log = context.logManager().getLog(I2PSimpleSession.class);
|
||||
_handlerMap = new SimpleMessageHandlerMap(context);
|
||||
_closed = true;
|
||||
_closing = false;
|
||||
_availabilityNotifier = new AvailabilityNotifier();
|
||||
if (options == null)
|
||||
options = System.getProperties();
|
||||
loadConfig(options);
|
||||
@@ -65,23 +61,32 @@ class I2PSimpleSession extends I2PSessionImpl2 {
|
||||
@Override
|
||||
public void connect() throws I2PSessionException {
|
||||
_closed = false;
|
||||
_availabilityNotifier.stopNotifying();
|
||||
I2PThread notifier = new I2PThread(_availabilityNotifier);
|
||||
notifier.setName("Simple Notifier");
|
||||
notifier.setDaemon(true);
|
||||
notifier.start();
|
||||
|
||||
try {
|
||||
// If we are in the router JVM, connect using the interal pseudo-socket
|
||||
_socket = InternalSocket.getSocket(_hostname, _portNum);
|
||||
_out = _socket.getOutputStream();
|
||||
synchronized (_out) {
|
||||
_out.write(I2PClient.PROTOCOL_BYTE);
|
||||
_out.flush();
|
||||
// If we are in the router JVM, connect using the interal queue
|
||||
if (_context.isRouterContext()) {
|
||||
// _socket, _out, and _writer remain null
|
||||
InternalClientManager mgr = _context.internalClientManager();
|
||||
if (mgr == null)
|
||||
throw new I2PSessionException("Router is not ready for connections");
|
||||
// the following may throw an I2PSessionException
|
||||
_queue = mgr.connect();
|
||||
_reader = new QueuedI2CPMessageReader(_queue, this);
|
||||
} else {
|
||||
if (Boolean.valueOf(getOptions().getProperty(PROP_ENABLE_SSL)).booleanValue())
|
||||
_socket = I2CPSSLSocketFactory.createSocket(_context, _hostname, _portNum);
|
||||
else
|
||||
_socket = new Socket(_hostname, _portNum);
|
||||
_out = _socket.getOutputStream();
|
||||
synchronized (_out) {
|
||||
_out.write(I2PClient.PROTOCOL_BYTE);
|
||||
_out.flush();
|
||||
}
|
||||
_writer = new ClientWriterRunner(_out, this);
|
||||
InputStream in = _socket.getInputStream();
|
||||
_reader = new I2CPMessageReader(in, this);
|
||||
}
|
||||
_writer = new ClientWriterRunner(_out, this);
|
||||
InputStream in = _socket.getInputStream();
|
||||
_reader = new I2CPMessageReader(in, this);
|
||||
// we do not receive payload messages, so we do not need an AvailabilityNotifier
|
||||
_reader.startReading();
|
||||
|
||||
} catch (UnknownHostException uhe) {
|
||||
@@ -93,57 +98,6 @@ class I2PSimpleSession extends I2PSessionImpl2 {
|
||||
}
|
||||
}
|
||||
|
||||
/** called by the message handler */
|
||||
void destReceived(Destination d) {
|
||||
_destReceived = true;
|
||||
_destination = d;
|
||||
synchronized (_destReceivedLock) {
|
||||
_destReceivedLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
void bwReceived(int[] i) {
|
||||
_bwReceived = true;
|
||||
_bwLimits = i;
|
||||
synchronized (_bwReceivedLock) {
|
||||
_bwReceivedLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Destination lookupDest(Hash h) throws I2PSessionException {
|
||||
if (_closed)
|
||||
return null;
|
||||
_destReceivedLock = new Object();
|
||||
sendMessage(new DestLookupMessage(h));
|
||||
for (int i = 0; i < 10 && !_destReceived; i++) {
|
||||
try {
|
||||
synchronized (_destReceivedLock) {
|
||||
_destReceivedLock.wait(1000);
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
_destReceived = false;
|
||||
return _destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] bandwidthLimits() throws I2PSessionException {
|
||||
if (_closed)
|
||||
return null;
|
||||
_bwReceivedLock = new Object();
|
||||
sendMessage(new GetBandwidthLimitsMessage());
|
||||
for (int i = 0; i < 5 && !_bwReceived; i++) {
|
||||
try {
|
||||
synchronized (_bwReceivedLock) {
|
||||
_bwReceivedLock.wait(1000);
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
_bwReceived = false;
|
||||
return _bwLimits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only map message handlers that we will use
|
||||
*/
|
||||
|
||||
@@ -37,9 +37,9 @@ public final class I2PDatagramDissector {
|
||||
|
||||
private Hash rxHash = null;
|
||||
|
||||
private Signature rxSign = new Signature();
|
||||
private Signature rxSign;
|
||||
|
||||
private Destination rxDest = new Destination();
|
||||
private Destination rxDest;
|
||||
|
||||
private byte[] rxPayload = new byte[DGRAM_BUFSIZE];
|
||||
|
||||
@@ -68,6 +68,9 @@ public final class I2PDatagramDissector {
|
||||
this.valid = false;
|
||||
|
||||
try {
|
||||
rxDest = new Destination();
|
||||
rxSign = new Signature();
|
||||
|
||||
// read destination
|
||||
rxDest.readBytes(dgStream);
|
||||
|
||||
@@ -153,6 +156,8 @@ public final class I2PDatagramDissector {
|
||||
* @return The Destination of the I2P repliable datagram sender
|
||||
*/
|
||||
public Destination extractSender() {
|
||||
if (this.rxDest == null)
|
||||
return null;
|
||||
Destination retDest = new Destination();
|
||||
try {
|
||||
retDest.fromByteArray(this.rxDest.toByteArray());
|
||||
@@ -184,6 +189,10 @@ public final class I2PDatagramDissector {
|
||||
if(this.valid)
|
||||
return;
|
||||
|
||||
if (rxSign == null || rxSign.getData() == null ||
|
||||
rxDest == null || rxDest.getSigningPublicKey() == null)
|
||||
throw new I2PInvalidDatagramException("Datagram not yet read");
|
||||
|
||||
// now validate
|
||||
if (!this.dsaEng.verifySignature(rxSign, rxHash.getData(), rxDest.getSigningPublicKey()))
|
||||
throw new I2PInvalidDatagramException("Incorrect I2P repliable datagram signature");
|
||||
|
||||
@@ -22,6 +22,13 @@ import net.i2p.data.Hash;
|
||||
*
|
||||
* All calls are blocking and return null on failure.
|
||||
* Timeout is set to 10 seconds in I2PSimpleSession.
|
||||
*
|
||||
* As of 0.8.3, standard I2PSessions support lookups,
|
||||
* including multiple lookups in parallel, and overriding
|
||||
* the default timeout.
|
||||
* Using an existing I2PSession is much more efficient and
|
||||
* flexible than using this class.
|
||||
*
|
||||
*/
|
||||
class LookupDest {
|
||||
|
||||
@@ -47,7 +54,7 @@ class LookupDest {
|
||||
|
||||
/** @param h 32 byte hash */
|
||||
static Destination lookupHash(I2PAppContext ctx, byte[] h) {
|
||||
Hash key = new Hash(h);
|
||||
Hash key = Hash.create(h);
|
||||
Destination rv = null;
|
||||
try {
|
||||
I2PClient client = new I2PSimpleClient();
|
||||
|
||||
@@ -22,13 +22,14 @@ import net.i2p.util.RandomSource;
|
||||
* See CryptixAESEngine for the real thing.
|
||||
*/
|
||||
public class AESEngine {
|
||||
private Log _log;
|
||||
private I2PAppContext _context;
|
||||
protected final Log _log;
|
||||
protected final I2PAppContext _context;
|
||||
|
||||
public AESEngine(I2PAppContext ctx) {
|
||||
_context = ctx;
|
||||
_log = _context.logManager().getLog(AESEngine.class);
|
||||
if (getClass() == AESEngine.class)
|
||||
_log.warn("Warning: AES is disabled");
|
||||
_log = _context.logManager().getLog(getClass());
|
||||
if (getClass().equals(AESEngine.class))
|
||||
_log.logAlways(Log.WARN, "AES is disabled");
|
||||
}
|
||||
|
||||
/** Encrypt the payload with the session key
|
||||
@@ -44,7 +45,10 @@ public class AESEngine {
|
||||
encrypt(payload, payloadIndex, out, outIndex, sessionKey, iv, 0, length);
|
||||
}
|
||||
|
||||
/** Encrypt the payload with the session key
|
||||
/**
|
||||
* Encrypt the payload with the session key.
|
||||
* This just copies payload to out, see extension for the real thing.
|
||||
*
|
||||
* @param payload data to be encrypted
|
||||
* @param payloadIndex index into the payload to start encrypting
|
||||
* @param out where to store the result
|
||||
@@ -55,7 +59,7 @@ public class AESEngine {
|
||||
*/
|
||||
public void encrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int ivOffset, int length) {
|
||||
System.arraycopy(payload, payloadIndex, out, outIndex, length);
|
||||
_log.warn("Warning: AES is disabled");
|
||||
_log.logAlways(Log.WARN, "AES is disabled");
|
||||
}
|
||||
|
||||
public byte[] safeEncrypt(byte payload[], SessionKey sessionKey, byte iv[], int paddedSize) {
|
||||
@@ -118,7 +122,6 @@ public class AESEngine {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/** Decrypt the data with the session key
|
||||
* @param payload data to be decrypted
|
||||
* @param payloadIndex index into the payload to start decrypting
|
||||
@@ -132,7 +135,10 @@ public class AESEngine {
|
||||
decrypt(payload, payloadIndex, out, outIndex, sessionKey, iv, 0, length);
|
||||
}
|
||||
|
||||
/** Decrypt the data with the session key
|
||||
/**
|
||||
* Decrypt the data with the session key.
|
||||
* This just copies payload to out, see extension for the real thing.
|
||||
*
|
||||
* @param payload data to be decrypted
|
||||
* @param payloadIndex index into the payload to start decrypting
|
||||
* @param out where to store the cleartext
|
||||
@@ -143,18 +149,20 @@ public class AESEngine {
|
||||
*/
|
||||
public void decrypt(byte payload[], int payloadIndex, byte out[], int outIndex, SessionKey sessionKey, byte iv[], int ivOffset, int length) {
|
||||
System.arraycopy(payload, payloadIndex, out, outIndex, length);
|
||||
_log.warn("Warning: AES is disabled");
|
||||
_log.logAlways(Log.WARN, "AES is disabled");
|
||||
}
|
||||
|
||||
/**
|
||||
* Just copies payload to out
|
||||
* This just copies payload to out, see extension for the real thing.
|
||||
* @param sessionKey unused
|
||||
*/
|
||||
public void encryptBlock(byte payload[], int inIndex, SessionKey sessionKey, byte out[], int outIndex) {
|
||||
System.arraycopy(payload, inIndex, out, outIndex, out.length - outIndex);
|
||||
}
|
||||
|
||||
/** decrypt the data with the session key provided
|
||||
/**
|
||||
* This just copies payload to rv, see extension for the real thing.
|
||||
*
|
||||
* @param payload encrypted data
|
||||
* @param sessionKey private session key
|
||||
*/
|
||||
|
||||
@@ -27,18 +27,16 @@ import net.i2p.util.Log;
|
||||
* @author jrandom, thecrypto
|
||||
*/
|
||||
public class CryptixAESEngine extends AESEngine {
|
||||
private Log _log;
|
||||
private final static CryptixRijndael_Algorithm _algo = new CryptixRijndael_Algorithm();
|
||||
private final static boolean USE_FAKE_CRYPTO = false;
|
||||
private final static byte FAKE_KEY = 0x2A;
|
||||
private CryptixAESKeyCache _cache;
|
||||
// keys are now cached in the SessionKey objects
|
||||
//private CryptixAESKeyCache _cache;
|
||||
|
||||
private static final ByteCache _prevCache = ByteCache.getInstance(16, 16);
|
||||
|
||||
public CryptixAESEngine(I2PAppContext context) {
|
||||
super(context);
|
||||
_log = context.logManager().getLog(CryptixAESEngine.class);
|
||||
_cache = new CryptixAESKeyCache();
|
||||
//_cache = new CryptixAESKeyCache();
|
||||
}
|
||||
|
||||
/** @param length must be a multiple of 16 */
|
||||
|
||||
@@ -8,6 +8,8 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
* data referenced in it is needed (which often is only one or two lines
|
||||
* of code)
|
||||
*
|
||||
* Unused as a class, as the keys are cached in the SessionKey objects,
|
||||
* but the static methods are used in FortunaStandalone.
|
||||
*/
|
||||
public final class CryptixAESKeyCache {
|
||||
private final LinkedBlockingQueue<KeyCacheEntry> _availableKeys;
|
||||
@@ -20,6 +22,9 @@ public final class CryptixAESKeyCache {
|
||||
|
||||
private static final int MAX_KEYS = 64;
|
||||
|
||||
/*
|
||||
* @deprecated unused, keys are now cached in the SessionKey objects
|
||||
*/
|
||||
public CryptixAESKeyCache() {
|
||||
_availableKeys = new LinkedBlockingQueue(MAX_KEYS);
|
||||
}
|
||||
@@ -27,6 +32,7 @@ public final class CryptixAESKeyCache {
|
||||
/**
|
||||
* Get the next available structure, either from the cache or a brand new one
|
||||
*
|
||||
* @deprecated unused, keys are now cached in the SessionKey objects
|
||||
*/
|
||||
public final KeyCacheEntry acquireKey() {
|
||||
KeyCacheEntry rv = _availableKeys.poll();
|
||||
@@ -38,6 +44,7 @@ public final class CryptixAESKeyCache {
|
||||
/**
|
||||
* Put this structure back onto the available cache for reuse
|
||||
*
|
||||
* @deprecated unused, keys are now cached in the SessionKey objects
|
||||
*/
|
||||
public final void releaseKey(KeyCacheEntry key) {
|
||||
_availableKeys.offer(key);
|
||||
|
||||
@@ -13,8 +13,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
@@ -48,14 +47,15 @@ import net.i2p.util.RandomSource;
|
||||
* @author jrandom
|
||||
*/
|
||||
public class DHSessionKeyBuilder {
|
||||
private static I2PAppContext _context = I2PAppContext.getGlobalContext();
|
||||
private final static Log _log = new Log(DHSessionKeyBuilder.class);
|
||||
private static int MIN_NUM_BUILDERS = -1;
|
||||
private static int MAX_NUM_BUILDERS = -1;
|
||||
private static int CALC_DELAY = -1;
|
||||
/* FIXME this should be final if you syncronize FIXME */
|
||||
private static volatile List _builders = new ArrayList(50);
|
||||
private static Thread _precalcThread = null;
|
||||
private static final I2PAppContext _context = I2PAppContext.getGlobalContext();
|
||||
private static final Log _log;
|
||||
private static final int MIN_NUM_BUILDERS;
|
||||
private static final int MAX_NUM_BUILDERS;
|
||||
private static final int CALC_DELAY;
|
||||
private static final LinkedBlockingQueue<DHSessionKeyBuilder> _builders;
|
||||
private static final Thread _precalcThread;
|
||||
|
||||
// the data of importance
|
||||
private BigInteger _myPrivateValue;
|
||||
private BigInteger _myPublicValue;
|
||||
private BigInteger _peerValue;
|
||||
@@ -65,17 +65,31 @@ public class DHSessionKeyBuilder {
|
||||
public final static String PROP_DH_PRECALC_MIN = "crypto.dh.precalc.min";
|
||||
public final static String PROP_DH_PRECALC_MAX = "crypto.dh.precalc.max";
|
||||
public final static String PROP_DH_PRECALC_DELAY = "crypto.dh.precalc.delay";
|
||||
public final static int DEFAULT_DH_PRECALC_MIN = 5;
|
||||
public final static int DEFAULT_DH_PRECALC_MAX = 50;
|
||||
public final static int DEFAULT_DH_PRECALC_DELAY = 10000;
|
||||
public final static int DEFAULT_DH_PRECALC_MIN = 15;
|
||||
public final static int DEFAULT_DH_PRECALC_MAX = 40;
|
||||
public final static int DEFAULT_DH_PRECALC_DELAY = 200;
|
||||
|
||||
/** check every 30 seconds whether we have less than the minimum */
|
||||
private static long _checkDelay = 30 * 1000;
|
||||
|
||||
static {
|
||||
I2PAppContext ctx = _context;
|
||||
ctx.statManager().createRateStat("crypto.dhGeneratePublicTime", "How long it takes to create x and X", "Encryption", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.dhCalculateSessionTime", "How long it takes to create the session key", "Encryption", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
|
||||
MIN_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MIN, DEFAULT_DH_PRECALC_MIN);
|
||||
MAX_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MAX, DEFAULT_DH_PRECALC_MAX);
|
||||
_log = ctx.logManager().getLog(DHSessionKeyBuilder.class);
|
||||
ctx.statManager().createRateStat("crypto.dhGeneratePublicTime", "How long it takes to create x and X", "Encryption", new long[] { 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.dhCalculateSessionTime", "How long it takes to create the session key", "Encryption", new long[] { 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.DHUsed", "Need a DH from the queue", "Encryption", new long[] { 60*60*1000 });
|
||||
ctx.statManager().createRateStat("crypto.DHEmpty", "DH queue empty", "Encryption", new long[] { 60*60*1000 });
|
||||
|
||||
// add to the defaults for every 128MB of RAM, up to 512MB
|
||||
long maxMemory = Runtime.getRuntime().maxMemory();
|
||||
int factor = Math.min(4, (int) (1 + (maxMemory / (128*1024*1024l))));
|
||||
int defaultMin = DEFAULT_DH_PRECALC_MIN * factor;
|
||||
int defaultMax = DEFAULT_DH_PRECALC_MAX * factor;
|
||||
MIN_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MIN, defaultMin);
|
||||
MAX_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MAX, defaultMax);
|
||||
|
||||
CALC_DELAY = ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY);
|
||||
_builders = new LinkedBlockingQueue(MAX_NUM_BUILDERS);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("DH Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
|
||||
@@ -90,40 +104,33 @@ public class DHSessionKeyBuilder {
|
||||
|
||||
/**
|
||||
* Construct a new DH key builder
|
||||
*
|
||||
* or pulls a prebuilt one from the queue.
|
||||
*/
|
||||
public DHSessionKeyBuilder() {
|
||||
this(false);
|
||||
DHSessionKeyBuilder builder = null;
|
||||
synchronized (_builders) {
|
||||
if (!_builders.isEmpty()) {
|
||||
builder = (DHSessionKeyBuilder) _builders.remove(0);
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Removing a builder. # left = " + _builders.size());
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN)) _log.warn("NO MORE BUILDERS! creating one now");
|
||||
}
|
||||
}
|
||||
_context.statManager().addRateData("crypto.DHUsed", 1, 0);
|
||||
DHSessionKeyBuilder builder = _builders.poll();
|
||||
if (builder != null) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("Removing a builder. # left = " + _builders.size());
|
||||
_myPrivateValue = builder._myPrivateValue;
|
||||
_myPublicValue = builder._myPublicValue;
|
||||
_peerValue = builder._peerValue;
|
||||
_sessionKey = builder._sessionKey;
|
||||
// these two are still null after precalc
|
||||
//_peerValue = builder._peerValue;
|
||||
//_sessionKey = builder._sessionKey;
|
||||
_extraExchangedBytes = builder._extraExchangedBytes;
|
||||
} else {
|
||||
_myPrivateValue = null;
|
||||
_myPublicValue = null;
|
||||
_peerValue = null;
|
||||
_sessionKey = null;
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("No more builders, creating one now");
|
||||
_context.statManager().addRateData("crypto.DHEmpty", 1, 0);
|
||||
// sets _myPrivateValue as a side effect
|
||||
_myPublicValue = generateMyValue();
|
||||
_extraExchangedBytes = new ByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public DHSessionKeyBuilder(boolean usePool) {
|
||||
_myPrivateValue = null;
|
||||
_myPublicValue = null;
|
||||
_peerValue = null;
|
||||
_sessionKey = null;
|
||||
/**
|
||||
* Only for internal use
|
||||
* @parameter usePool unused, just to make it different from other constructor
|
||||
*/
|
||||
private DHSessionKeyBuilder(boolean usePool) {
|
||||
_extraExchangedBytes = new ByteArray();
|
||||
}
|
||||
|
||||
@@ -189,18 +196,12 @@ public class DHSessionKeyBuilder {
|
||||
}
|
||||
|
||||
private static final int getSize() {
|
||||
synchronized (_builders) {
|
||||
return _builders.size();
|
||||
}
|
||||
}
|
||||
|
||||
private static final int addBuilder(DHSessionKeyBuilder builder) {
|
||||
int sz = 0;
|
||||
synchronized (_builders) {
|
||||
_builders.add(builder);
|
||||
sz = _builders.size();
|
||||
}
|
||||
return sz;
|
||||
/** @return true if successful, false if full */
|
||||
private static final boolean addBuilder(DHSessionKeyBuilder builder) {
|
||||
return _builders.offer(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,7 +211,7 @@ public class DHSessionKeyBuilder {
|
||||
*/
|
||||
public BigInteger generateMyValue() {
|
||||
long start = System.currentTimeMillis();
|
||||
_myPrivateValue = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, RandomSource.getInstance());
|
||||
_myPrivateValue = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, _context.random());
|
||||
BigInteger myValue = CryptoConstants.elgg.modPow(_myPrivateValue, CryptoConstants.elgp);
|
||||
long end = System.currentTimeMillis();
|
||||
long diff = end - start;
|
||||
@@ -314,6 +315,7 @@ public class DHSessionKeyBuilder {
|
||||
* If there aren't enough bytes (with all of them being consumed by the 32 byte key),
|
||||
* the SHA256 of the key itself is used.
|
||||
*
|
||||
* @return non-null (but rv.getData() may be null)
|
||||
*/
|
||||
public ByteArray getExtraBytes() {
|
||||
return _extraExchangedBytes;
|
||||
@@ -406,6 +408,7 @@ public class DHSessionKeyBuilder {
|
||||
}
|
||||
*/
|
||||
|
||||
/******
|
||||
public static void main(String args[]) {
|
||||
//if (true) { testValidation(); return; }
|
||||
|
||||
@@ -419,7 +422,7 @@ public class DHSessionKeyBuilder {
|
||||
long negTime = 0;
|
||||
try {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
long startNeg = Clock.getInstance().now();
|
||||
long startNeg = System.currentTimeMillis();
|
||||
DHSessionKeyBuilder builder1 = new DHSessionKeyBuilder();
|
||||
DHSessionKeyBuilder builder2 = new DHSessionKeyBuilder();
|
||||
BigInteger pub1 = builder1.getMyPublicValue();
|
||||
@@ -428,7 +431,7 @@ public class DHSessionKeyBuilder {
|
||||
builder1.setPeerPublicValue(pub2);
|
||||
SessionKey key1 = builder1.getSessionKey();
|
||||
SessionKey key2 = builder2.getSessionKey();
|
||||
long endNeg = Clock.getInstance().now();
|
||||
long endNeg = System.currentTimeMillis();
|
||||
negTime += endNeg - startNeg;
|
||||
|
||||
if (!key1.equals(key2))
|
||||
@@ -458,10 +461,11 @@ public class DHSessionKeyBuilder {
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
}
|
||||
******/
|
||||
|
||||
private static class DHSessionKeyBuilderPrecalcRunner implements Runnable {
|
||||
private int _minSize;
|
||||
private int _maxSize;
|
||||
private final int _minSize;
|
||||
private final int _maxSize;
|
||||
|
||||
private DHSessionKeyBuilderPrecalcRunner(int minSize, int maxSize) {
|
||||
_minSize = minSize;
|
||||
@@ -472,22 +476,28 @@ public class DHSessionKeyBuilder {
|
||||
while (true) {
|
||||
|
||||
int curSize = 0;
|
||||
long start = Clock.getInstance().now();
|
||||
long start = System.currentTimeMillis();
|
||||
int startSize = getSize();
|
||||
// Adjust delay
|
||||
if (startSize <= (_minSize * 2 / 3) && _checkDelay > 1000)
|
||||
_checkDelay -= 1000;
|
||||
else if (startSize > (_minSize * 3 / 2) && _checkDelay < 60*1000)
|
||||
_checkDelay += 1000;
|
||||
curSize = startSize;
|
||||
while (curSize < _minSize) {
|
||||
while (curSize < _maxSize) {
|
||||
if (curSize < _minSize) {
|
||||
for (int i = curSize; i < _maxSize; i++) {
|
||||
long curStart = System.currentTimeMillis();
|
||||
curSize = addBuilder(precalc(curSize));
|
||||
if (!addBuilder(precalc()))
|
||||
break;
|
||||
long curCalc = System.currentTimeMillis() - curStart;
|
||||
// for some relief...
|
||||
try {
|
||||
Thread.sleep(CALC_DELAY + curCalc * 10);
|
||||
Thread.sleep(CALC_DELAY + (curCalc * 3));
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
}
|
||||
}
|
||||
long end = Clock.getInstance().now();
|
||||
long end = System.currentTimeMillis();
|
||||
int numCalc = curSize - startSize;
|
||||
if (numCalc > 0) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@@ -496,16 +506,15 @@ public class DHSessionKeyBuilder {
|
||||
+ (CALC_DELAY * numCalc) + "ms relief). now sleeping");
|
||||
}
|
||||
try {
|
||||
Thread.sleep(30 * 1000);
|
||||
Thread.sleep(_checkDelay);
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DHSessionKeyBuilder precalc(int i) {
|
||||
private static DHSessionKeyBuilder precalc() {
|
||||
DHSessionKeyBuilder builder = new DHSessionKeyBuilder(false);
|
||||
builder.getMyPublicValue();
|
||||
//_log.debug("Precalc " + i + " complete");
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,12 +38,13 @@ import net.i2p.data.Hash;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.SigningPublicKey;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.NativeBigInteger;
|
||||
|
||||
/**
|
||||
* Params and rv's changed from Hash to SHA1Hash for version 0.8.1
|
||||
* There shouldn't be any external users of those variants.
|
||||
* Hash variants of sign() and verifySignature() restored in 0.8.3, required by Syndie.
|
||||
*/
|
||||
public class DSAEngine {
|
||||
private Log _log;
|
||||
@@ -68,6 +69,22 @@ public class DSAEngine {
|
||||
|
||||
/** @param hash SHA-1 hash, NOT a SHA-256 hash */
|
||||
public boolean verifySignature(Signature signature, SHA1Hash hash, SigningPublicKey verifyingKey) {
|
||||
return verifySig(signature, hash, verifyingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by Syndie.
|
||||
* @since 0.8.3 (restored, was removed in 0.8.1 and 0.8.2)
|
||||
*/
|
||||
public boolean verifySignature(Signature signature, Hash hash, SigningPublicKey verifyingKey) {
|
||||
return verifySig(signature, hash, verifyingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hash either a Hash or a SHA1Hash
|
||||
* @since 0.8.3
|
||||
*/
|
||||
private boolean verifySig(Signature signature, SimpleDataStructure hash, SigningPublicKey verifyingKey) {
|
||||
long start = _context.clock().now();
|
||||
|
||||
try {
|
||||
@@ -129,6 +146,22 @@ public class DSAEngine {
|
||||
|
||||
/** @param hash SHA-1 hash, NOT a SHA-256 hash */
|
||||
public Signature sign(SHA1Hash hash, SigningPrivateKey signingKey) {
|
||||
return signIt(hash, signingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by Syndie.
|
||||
* @since 0.8.3 (restored, was removed in 0.8.1 and 0.8.2)
|
||||
*/
|
||||
public Signature sign(Hash hash, SigningPrivateKey signingKey) {
|
||||
return signIt(hash, signingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hash either a Hash or a SHA1Hash
|
||||
* @since 0.8.3
|
||||
*/
|
||||
private Signature signIt(SimpleDataStructure hash, SigningPrivateKey signingKey) {
|
||||
if ((signingKey == null) || (hash == null)) return null;
|
||||
long start = _context.clock().now();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user