forked from I2P_Developers/i2p.i2p
Transports:
- More transition to status enum - Don't set TCP keepalive for IPv6
This commit is contained in:
@ -36,20 +36,22 @@ fi
|
|||||||
# list specific files in core/ and router/ here, so we don't scan the whole tree
|
# list specific files in core/ and router/ here, so we don't scan the whole tree
|
||||||
ROUTERFILES="\
|
ROUTERFILES="\
|
||||||
../../../core/java/src/net/i2p/data/DataHelper.java \
|
../../../core/java/src/net/i2p/data/DataHelper.java \
|
||||||
../../../core/java/src/net/i2p/util/LogWriter.java \
|
|
||||||
../../../router/java/src/net/i2p/router/tasks/CoalesceStatsEvent.java \
|
|
||||||
../../../router/java/src/net/i2p/router/RouterThrottleImpl.java \
|
|
||||||
../../../router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java \
|
|
||||||
../../../router/java/src/net/i2p/router/transport/TransportManager.java \
|
|
||||||
../../../router/java/src/net/i2p/router/transport/GetBidsJob.java \
|
|
||||||
../../../router/java/src/net/i2p/router/Blocklist.java \
|
../../../router/java/src/net/i2p/router/Blocklist.java \
|
||||||
../../../router/java/src/net/i2p/router/transport/ntcp/EstablishState.java \
|
../../../router/java/src/net/i2p/router/CommSystemFacade.java \
|
||||||
|
../../../router/java/src/net/i2p/router/RouterThrottleImpl.java \
|
||||||
../../../router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java \
|
../../../router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java \
|
||||||
|
../../../router/java/src/net/i2p/router/tasks/CoalesceStatsEvent.java \
|
||||||
../../../router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java \
|
../../../router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java \
|
||||||
|
../../../router/java/src/net/i2p/router/transport/GetBidsJob.java \
|
||||||
|
../../../router/java/src/net/i2p/router/transport/TransportManager.java \
|
||||||
|
../../../router/java/src/net/i2p/router/transport/UPnP.java \
|
||||||
|
../../../router/java/src/net/i2p/router/transport/UPnPManager.java \
|
||||||
|
../../../router/java/src/net/i2p/router/transport/ntcp/EstablishState.java \
|
||||||
../../../router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java \
|
../../../router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java \
|
||||||
../../../router/java/src/net/i2p/router/transport/udp/UDPTransport.java \
|
../../../router/java/src/net/i2p/router/transport/udp/UDPTransport.java \
|
||||||
../../../router/java/src/net/i2p/router/transport/UPnP.java \
|
../../../router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java \
|
||||||
../../../router/java/src/net/i2p/router/transport/UPnPManager.java"
|
../../../core/java/src/net/i2p/util/LogWriter.java \
|
||||||
|
"
|
||||||
|
|
||||||
# add ../java/ so the refs will work in the po file
|
# add ../java/ so the refs will work in the po file
|
||||||
JPATHS="../java/src ../jsp/WEB-INF ../java/strings $ROUTERFILES"
|
JPATHS="../java/src ../jsp/WEB-INF ../java/strings $ROUTERFILES"
|
||||||
|
@ -7,7 +7,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.router.RouterAddress;
|
import net.i2p.data.router.RouterAddress;
|
||||||
import net.i2p.router.CommSystemFacade;
|
import net.i2p.router.CommSystemFacade.Status;
|
||||||
import net.i2p.router.Router;
|
import net.i2p.router.Router;
|
||||||
import net.i2p.router.transport.TransportManager;
|
import net.i2p.router.transport.TransportManager;
|
||||||
import net.i2p.router.transport.TransportUtil;
|
import net.i2p.router.transport.TransportUtil;
|
||||||
@ -148,14 +148,18 @@ public class ConfigNetHelper extends HelperBase {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This isn't updated for the new statuses, but it's commented out in the jsp.
|
||||||
|
* @deprecated unused, to be fixed if needed
|
||||||
|
*/
|
||||||
public String getRequireIntroductionsChecked() {
|
public String getRequireIntroductionsChecked() {
|
||||||
short status = _context.commSystem().getReachabilityStatus();
|
Status status = _context.commSystem().getStatus();
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case CommSystemFacade.STATUS_OK:
|
case OK:
|
||||||
case CommSystemFacade.STATUS_UNKNOWN:
|
case UNKNOWN:
|
||||||
return getChecked(UDPTransport.PROP_FORCE_INTRODUCERS);
|
return getChecked(UDPTransport.PROP_FORCE_INTRODUCERS);
|
||||||
case CommSystemFacade.STATUS_DIFFERENT:
|
case DIFFERENT:
|
||||||
case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
|
case REJECT_UNSOLICITED:
|
||||||
default:
|
default:
|
||||||
return CHECKED;
|
return CHECKED;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ import net.i2p.data.Hash;
|
|||||||
import net.i2p.data.LeaseSet;
|
import net.i2p.data.LeaseSet;
|
||||||
import net.i2p.data.router.RouterAddress;
|
import net.i2p.data.router.RouterAddress;
|
||||||
import net.i2p.data.router.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.router.CommSystemFacade;
|
import net.i2p.router.CommSystemFacade.Status;
|
||||||
import net.i2p.router.Router;
|
import net.i2p.router.Router;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.RouterVersion;
|
import net.i2p.router.RouterVersion;
|
||||||
@ -154,34 +154,48 @@ public class SummaryHelper extends HelperBase {
|
|||||||
if (routerInfo == null)
|
if (routerInfo == null)
|
||||||
return _("Testing");
|
return _("Testing");
|
||||||
|
|
||||||
int status = _context.commSystem().getReachabilityStatus();
|
Status status = _context.commSystem().getStatus();
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case CommSystemFacade.STATUS_OK:
|
case OK:
|
||||||
|
case IPV4_OK_IPV6_UNKNOWN:
|
||||||
|
case IPV4_OK_IPV6_FIREWALLED:
|
||||||
|
case IPV4_UNKNOWN_IPV6_OK:
|
||||||
|
case IPV4_FIREWALLED_IPV6_OK:
|
||||||
|
case IPV4_DISABLED_IPV6_OK:
|
||||||
RouterAddress ra = routerInfo.getTargetAddress("NTCP");
|
RouterAddress ra = routerInfo.getTargetAddress("NTCP");
|
||||||
if (ra == null)
|
if (ra == null)
|
||||||
return _("OK");
|
return _(status.toStatusString());
|
||||||
byte[] ip = ra.getIP();
|
byte[] ip = ra.getIP();
|
||||||
if (ip == null)
|
if (ip == null)
|
||||||
return _("ERR-Unresolved TCP Address");
|
return _("ERR-Unresolved TCP Address");
|
||||||
// TODO set IPv6 arg based on configuration?
|
// TODO set IPv6 arg based on configuration?
|
||||||
if (TransportUtil.isPubliclyRoutable(ip, true))
|
if (TransportUtil.isPubliclyRoutable(ip, true))
|
||||||
return _("OK");
|
return _(status.toStatusString());
|
||||||
return _("ERR-Private TCP Address");
|
return _("ERR-Private TCP Address");
|
||||||
case CommSystemFacade.STATUS_DIFFERENT:
|
|
||||||
|
case DIFFERENT:
|
||||||
return _("ERR-SymmetricNAT");
|
return _("ERR-SymmetricNAT");
|
||||||
case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
|
|
||||||
|
case REJECT_UNSOLICITED:
|
||||||
|
case IPV4_FIREWALLED_IPV6_UNKNOWN:
|
||||||
|
case IPV4_DISABLED_IPV6_FIREWALLED:
|
||||||
if (routerInfo.getTargetAddress("NTCP") != null)
|
if (routerInfo.getTargetAddress("NTCP") != null)
|
||||||
return _("WARN-Firewalled with Inbound TCP Enabled");
|
return _("WARN-Firewalled with Inbound TCP Enabled");
|
||||||
if (((FloodfillNetworkDatabaseFacade)_context.netDb()).floodfillEnabled())
|
if (((FloodfillNetworkDatabaseFacade)_context.netDb()).floodfillEnabled())
|
||||||
return _("WARN-Firewalled and Floodfill");
|
return _("WARN-Firewalled and Floodfill");
|
||||||
//if (_context.router().getRouterInfo().getCapabilities().indexOf('O') >= 0)
|
//if (_context.router().getRouterInfo().getCapabilities().indexOf('O') >= 0)
|
||||||
// return _("WARN-Firewalled and Fast");
|
// return _("WARN-Firewalled and Fast");
|
||||||
return _("Firewalled");
|
return _(status.toStatusString());
|
||||||
case CommSystemFacade.STATUS_DISCONNECTED:
|
|
||||||
|
case DISCONNECTED:
|
||||||
return _("Disconnected - check network cable");
|
return _("Disconnected - check network cable");
|
||||||
case CommSystemFacade.STATUS_HOSED:
|
|
||||||
|
case HOSED:
|
||||||
return _("ERR-UDP Port In Use - Set i2np.udp.internalPort=xxxx in advanced config and restart");
|
return _("ERR-UDP Port In Use - Set i2np.udp.internalPort=xxxx in advanced config and restart");
|
||||||
case CommSystemFacade.STATUS_UNKNOWN: // fallthrough
|
|
||||||
|
case UNKNOWN:
|
||||||
|
case IPV4_UNKNOWN_IPV6_FIREWALLED:
|
||||||
|
case IPV4_DISABLED_IPV6_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
ra = routerInfo.getTargetAddress("SSU");
|
ra = routerInfo.getTargetAddress("SSU");
|
||||||
if (ra == null && _context.router().getUptime() > 5*60*1000) {
|
if (ra == null && _context.router().getUptime() > 5*60*1000) {
|
||||||
@ -193,7 +207,7 @@ public class SummaryHelper extends HelperBase {
|
|||||||
else
|
else
|
||||||
return _("WARN-Firewalled with UDP Disabled");
|
return _("WARN-Firewalled with UDP Disabled");
|
||||||
}
|
}
|
||||||
return _("Testing");
|
return _(status.toStatusString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -922,17 +922,26 @@ public class Router implements RouterClock.ClockShiftListener {
|
|||||||
}
|
}
|
||||||
switch (_context.commSystem().getStatus()) {
|
switch (_context.commSystem().getStatus()) {
|
||||||
case OK:
|
case OK:
|
||||||
|
case IPV4_OK_IPV6_UNKNOWN:
|
||||||
|
case IPV4_OK_IPV6_FIREWALLED:
|
||||||
|
case IPV4_FIREWALLED_IPV6_OK:
|
||||||
|
case IPV4_DISABLED_IPV6_OK:
|
||||||
|
case IPV4_UNKNOWN_IPV6_OK:
|
||||||
ri.addCapability(CAPABILITY_REACHABLE);
|
ri.addCapability(CAPABILITY_REACHABLE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DIFFERENT:
|
case DIFFERENT:
|
||||||
case REJECT_UNSOLICITED:
|
case REJECT_UNSOLICITED:
|
||||||
|
case IPV4_DISABLED_IPV6_FIREWALLED:
|
||||||
ri.addCapability(CAPABILITY_UNREACHABLE);
|
ri.addCapability(CAPABILITY_UNREACHABLE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DISCONNECTED:
|
case DISCONNECTED:
|
||||||
case HOSED:
|
case HOSED:
|
||||||
case UNKNOWN:
|
case UNKNOWN:
|
||||||
|
case IPV4_UNKNOWN_IPV6_FIREWALLED:
|
||||||
|
case IPV4_DISABLED_IPV6_UNKNOWN:
|
||||||
|
case IPV4_FIREWALLED_IPV6_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
// no explicit capability
|
// no explicit capability
|
||||||
break;
|
break;
|
||||||
|
@ -13,7 +13,7 @@ import java.util.Set;
|
|||||||
import net.i2p.data.DatabaseEntry;
|
import net.i2p.data.DatabaseEntry;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.router.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.router.CommSystemFacade;
|
import net.i2p.router.CommSystemFacade.Status;
|
||||||
import net.i2p.router.JobImpl;
|
import net.i2p.router.JobImpl;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
@ -43,7 +43,7 @@ class ExpireRoutersJob extends JobImpl {
|
|||||||
public String getName() { return "Expire Routers Job"; }
|
public String getName() { return "Expire Routers Job"; }
|
||||||
|
|
||||||
public void runJob() {
|
public void runJob() {
|
||||||
if (getContext().commSystem().getReachabilityStatus() != CommSystemFacade.STATUS_DISCONNECTED) {
|
if (getContext().commSystem().getStatus() != Status.DISCONNECTED) {
|
||||||
int removed = expireKeys();
|
int removed = expireKeys();
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Routers expired: " + removed);
|
_log.info("Routers expired: " + removed);
|
||||||
|
@ -18,7 +18,7 @@ import net.i2p.data.i2np.I2NPMessage;
|
|||||||
import net.i2p.data.router.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.kademlia.KBucketSet;
|
import net.i2p.kademlia.KBucketSet;
|
||||||
import net.i2p.kademlia.XORComparator;
|
import net.i2p.kademlia.XORComparator;
|
||||||
import net.i2p.router.CommSystemFacade;
|
import net.i2p.router.CommSystemFacade.Status;
|
||||||
import net.i2p.router.Job;
|
import net.i2p.router.Job;
|
||||||
import net.i2p.router.MessageSelector;
|
import net.i2p.router.MessageSelector;
|
||||||
import net.i2p.router.OutNetMessage;
|
import net.i2p.router.OutNetMessage;
|
||||||
@ -509,7 +509,7 @@ class IterativeSearchJob extends FloodSearchJob {
|
|||||||
_dead = true;
|
_dead = true;
|
||||||
}
|
}
|
||||||
_facade.complete(_key);
|
_facade.complete(_key);
|
||||||
if (getContext().commSystem().getReachabilityStatus() != CommSystemFacade.STATUS_DISCONNECTED)
|
if (getContext().commSystem().getStatus() != Status.DISCONNECTED)
|
||||||
_facade.lookupFailed(_key);
|
_facade.lookupFailed(_key);
|
||||||
getContext().messageRegistry().unregisterPending(_out);
|
getContext().messageRegistry().unregisterPending(_out);
|
||||||
int tries;
|
int tries;
|
||||||
|
@ -2,7 +2,7 @@ package net.i2p.router.tasks;
|
|||||||
|
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.router.Job;
|
import net.i2p.router.Job;
|
||||||
import net.i2p.router.CommSystemFacade;
|
import net.i2p.router.CommSystemFacade.Status;
|
||||||
import net.i2p.router.Router;
|
import net.i2p.router.Router;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.util.EventLog;
|
import net.i2p.router.util.EventLog;
|
||||||
@ -133,7 +133,7 @@ public class RouterWatchdog implements Runnable {
|
|||||||
boolean ok = verifyJobQueueLiveliness();
|
boolean ok = verifyJobQueueLiveliness();
|
||||||
// If we aren't connected to the network that's why there's nobody to talk to
|
// If we aren't connected to the network that's why there's nobody to talk to
|
||||||
long netErrors = 0;
|
long netErrors = 0;
|
||||||
if (_context.commSystem().getReachabilityStatus() == CommSystemFacade.STATUS_DISCONNECTED) {
|
if (_context.commSystem().getStatus() == Status.DISCONNECTED) {
|
||||||
netErrors = 10;
|
netErrors = 10;
|
||||||
} else {
|
} else {
|
||||||
RateStat rs = _context.statManager().getRate("udp.sendException");
|
RateStat rs = _context.statManager().getRate("udp.sendException");
|
||||||
|
@ -650,6 +650,11 @@ public class TransportManager implements TransportEventListener {
|
|||||||
* will take many seconds if it has vanished.
|
* will take many seconds if it has vanished.
|
||||||
*/
|
*/
|
||||||
public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException {
|
public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException {
|
||||||
|
out.write("<p>");
|
||||||
|
out.write(_("Status"));
|
||||||
|
out.write(": ");
|
||||||
|
out.write(_(getReachabilityStatus().toStatusString()));
|
||||||
|
out.write("</p>");
|
||||||
TreeMap<String, Transport> transports = new TreeMap<String, Transport>();
|
TreeMap<String, Transport> transports = new TreeMap<String, Transport>();
|
||||||
for (Transport t : _transports.values()) {
|
for (Transport t : _transports.values()) {
|
||||||
transports.put(t.getStyle(), t);
|
transports.put(t.getStyle(), t);
|
||||||
|
@ -2,6 +2,7 @@ package net.i2p.router.transport.ntcp;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.net.Inet6Address;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.CancelledKeyException;
|
import java.nio.channels.CancelledKeyException;
|
||||||
@ -24,7 +25,7 @@ import net.i2p.I2PAppContext;
|
|||||||
import net.i2p.data.ByteArray;
|
import net.i2p.data.ByteArray;
|
||||||
import net.i2p.data.router.RouterAddress;
|
import net.i2p.data.router.RouterAddress;
|
||||||
import net.i2p.data.router.RouterIdentity;
|
import net.i2p.data.router.RouterIdentity;
|
||||||
import net.i2p.router.CommSystemFacade;
|
import net.i2p.router.CommSystemFacade.Status;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.transport.FIFOBandwidthLimiter;
|
import net.i2p.router.transport.FIFOBandwidthLimiter;
|
||||||
import net.i2p.util.Addresses;
|
import net.i2p.util.Addresses;
|
||||||
@ -546,7 +547,7 @@ class EventPumper implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BUGFIX for firewalls. --Sponge
|
// BUGFIX for firewalls. --Sponge
|
||||||
if (_context.commSystem().getReachabilityStatus() != CommSystemFacade.STATUS_OK)
|
if (shouldSetKeepAlive(chan))
|
||||||
chan.socket().setKeepAlive(true);
|
chan.socket().setKeepAlive(true);
|
||||||
|
|
||||||
SelectionKey ckey = chan.register(_selector, SelectionKey.OP_READ);
|
SelectionKey ckey = chan.register(_selector, SelectionKey.OP_READ);
|
||||||
@ -567,7 +568,7 @@ class EventPumper implements Runnable {
|
|||||||
_log.debug("processing connect for " + con + ": connected? " + connected);
|
_log.debug("processing connect for " + con + ": connected? " + connected);
|
||||||
if (connected) {
|
if (connected) {
|
||||||
// BUGFIX for firewalls. --Sponge
|
// BUGFIX for firewalls. --Sponge
|
||||||
if (_context.commSystem().getReachabilityStatus() != CommSystemFacade.STATUS_OK)
|
if (shouldSetKeepAlive(chan))
|
||||||
chan.socket().setKeepAlive(true);
|
chan.socket().setKeepAlive(true);
|
||||||
con.setKey(key);
|
con.setKey(key);
|
||||||
con.outboundConnected();
|
con.outboundConnected();
|
||||||
@ -591,6 +592,20 @@ class EventPumper implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.9.20
|
||||||
|
*/
|
||||||
|
private boolean shouldSetKeepAlive(SocketChannel chan) {
|
||||||
|
if (chan.socket().getInetAddress() instanceof Inet6Address)
|
||||||
|
return false;
|
||||||
|
Status status = _context.commSystem().getStatus();
|
||||||
|
if (status == Status.OK ||
|
||||||
|
status == Status.IPV4_OK_IPV6_UNKNOWN ||
|
||||||
|
status == Status.IPV4_OK_IPV6_FIREWALLED)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OP_READ will always be set before this is called.
|
* OP_READ will always be set before this is called.
|
||||||
* This method will disable the interest if no more reads remain because of inbound bandwidth throttling.
|
* This method will disable the interest if no more reads remain because of inbound bandwidth throttling.
|
||||||
|
@ -11,7 +11,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.i2np.I2NPMessage;
|
import net.i2p.data.i2np.I2NPMessage;
|
||||||
import net.i2p.data.router.RouterInfo;
|
import net.i2p.data.router.RouterInfo;
|
||||||
import net.i2p.router.CommSystemFacade;
|
import net.i2p.router.CommSystemFacade.Status;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.TunnelManagerFacade;
|
import net.i2p.router.TunnelManagerFacade;
|
||||||
import net.i2p.stat.Rate;
|
import net.i2p.stat.Rate;
|
||||||
@ -106,7 +106,7 @@ class BuildExecutor implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int allowed() {
|
private int allowed() {
|
||||||
if (_context.commSystem().getReachabilityStatus() == CommSystemFacade.STATUS_DISCONNECTED)
|
if (_context.commSystem().getStatus() == Status.DISCONNECTED)
|
||||||
return 0;
|
return 0;
|
||||||
int maxKBps = _context.bandwidthLimiter().getOutboundKBytesPerSecond();
|
int maxKBps = _context.bandwidthLimiter().getOutboundKBytesPerSecond();
|
||||||
int allowed = maxKBps / 6; // Max. 1 concurrent build per 6 KB/s outbound
|
int allowed = maxKBps / 6; // Max. 1 concurrent build per 6 KB/s outbound
|
||||||
|
Reference in New Issue
Block a user