forked from I2P_Developers/i2p.i2p
Compare commits
9 Commits
i2p.i2p.2.
...
dynamic-on
Author | SHA1 | Date | |
---|---|---|---|
0605977776 | |||
714adbdf10 | |||
fe1e245c25 | |||
b02389a0a4 | |||
171263e3ab | |||
c0bd91daec | |||
39a95e457a | |||
8414cb8eae | |||
2aa109bc2e |
@ -27,7 +27,12 @@ public class ConfigReseedHandler extends FormHandler {
|
|||||||
ReseedChecker checker = _context.netDb().reseedChecker();
|
ReseedChecker checker = _context.netDb().reseedChecker();
|
||||||
if (_action.equals(_t("Save changes and reseed now"))) {
|
if (_action.equals(_t("Save changes and reseed now"))) {
|
||||||
saveChanges();
|
saveChanges();
|
||||||
if (!checker.requestReseed()) {
|
if (checker.onionReseedsConfigured()) {
|
||||||
|
if (!checker.requestOnionReseed()) {
|
||||||
|
addFormError(_t("Onion reseeding is already in progress"));
|
||||||
|
addCheckerStatus(checker);
|
||||||
|
}
|
||||||
|
} else if (!checker.requestReseed()) {
|
||||||
addFormError(_t("Reseeding is already in progress"));
|
addFormError(_t("Reseeding is already in progress"));
|
||||||
addCheckerStatus(checker);
|
addCheckerStatus(checker);
|
||||||
} else {
|
} else {
|
||||||
@ -51,15 +56,17 @@ public class ConfigReseedHandler extends FormHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (!checker.requestReseed(url)) {
|
if (url.getHost().endsWith(".onion")) {
|
||||||
addFormError(_t("Reseeding is already in progress"));
|
if (!checker.requestOnionReseed(url)) {
|
||||||
|
addFormError(_t("Tor not available, unable to perform onion reseed"));
|
||||||
addCheckerStatus(checker);
|
addCheckerStatus(checker);
|
||||||
} else {
|
} else {
|
||||||
// wait a while for completion but not forever
|
// wait a while for completion but not forever
|
||||||
for (int i = 0; i < 40; i++) {
|
for (int i = 0; i < 40; i++) {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(500);
|
Thread.sleep(500);
|
||||||
} catch (InterruptedException ie) {}
|
} catch (InterruptedException ie) {
|
||||||
|
}
|
||||||
if (!checker.inProgress())
|
if (!checker.inProgress())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -71,6 +78,29 @@ public class ConfigReseedHandler extends FormHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
if (!checker.requestReseed(url)) {
|
||||||
|
addFormError(_t("Reseeding is already in progress"));
|
||||||
|
addCheckerStatus(checker);
|
||||||
|
} else {
|
||||||
|
// wait a while for completion but not forever
|
||||||
|
for (int i = 0; i < 40; i++) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(500);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
}
|
||||||
|
if (!checker.inProgress())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!addCheckerStatus(checker)) {
|
||||||
|
if (checker.inProgress()) {
|
||||||
|
addFormNotice(_t("Reseed in progress, check sidebar for status"));
|
||||||
|
} else {
|
||||||
|
addFormNotice(_t("Reseed complete, check sidebar for status"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (IllegalArgumentException iae) {
|
||||||
addFormError(_t("Bad URL {0}", val) + " - " + iae.getLocalizedMessage());
|
addFormError(_t("Bad URL {0}", val) + " - " + iae.getLocalizedMessage());
|
||||||
}
|
}
|
||||||
@ -98,14 +128,19 @@ public class ConfigReseedHandler extends FormHandler {
|
|||||||
} finally {
|
} finally {
|
||||||
// it's really a ByteArrayInputStream but we'll play along...
|
// it's really a ByteArrayInputStream but we'll play along...
|
||||||
if (in != null)
|
if (in != null)
|
||||||
try { in.close(); } catch (IOException ioe) {}
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (_action.equals(_t("Save changes"))) {
|
} else if (_action.equals(_t("Save changes"))) {
|
||||||
saveChanges();
|
saveChanges();
|
||||||
} else if (_action.equals(_t("Reset URL list"))) {
|
} else if (_action.equals(_t("Reset URL list"))) {
|
||||||
resetUrlList();
|
resetUrlList();
|
||||||
|
} else if (_action.equals(_t("Reset Onion URL list"))) {
|
||||||
|
resetOnionUrlList();
|
||||||
}
|
}
|
||||||
//addFormError(_t("Unsupported") + ' ' + _action + '.');
|
// addFormError(_t("Unsupported") + ' ' + _action + '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -133,6 +168,13 @@ public class ConfigReseedHandler extends FormHandler {
|
|||||||
addFormError(_t("Error saving the configuration (applied but not saved) - please see the error logs"));
|
addFormError(_t("Error saving the configuration (applied but not saved) - please see the error logs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resetOnionUrlList() {
|
||||||
|
if (_context.router().saveConfig(Reseeder.PROP_ONION_RESEED_URL, null))
|
||||||
|
addFormNotice(_t("URL list reset successfully"));
|
||||||
|
else
|
||||||
|
addFormError(_t("Error saving the configuration (applied but not saved) - please see the error logs"));
|
||||||
|
}
|
||||||
|
|
||||||
/** @since 0.8.9 */
|
/** @since 0.8.9 */
|
||||||
private void saveString(String config, String param) {
|
private void saveString(String config, String param) {
|
||||||
String val = getJettyString(param);
|
String val = getJettyString(param);
|
||||||
@ -169,6 +211,16 @@ public class ConfigReseedHandler extends FormHandler {
|
|||||||
changes.put(Reseeder.PROP_RESEED_URL, url);
|
changes.put(Reseeder.PROP_RESEED_URL, url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
String onionurl = getJettyString("onionReseedURL");
|
||||||
|
if (onionurl != null) {
|
||||||
|
onionurl = onionurl.trim().replace("\r\n", ",").replace("\n", ",");
|
||||||
|
if (onionurl.length() <= 0) {
|
||||||
|
addFormNotice("Restoring default URLs");
|
||||||
|
removes.add(Reseeder.PROP_ONION_RESEED_URL);
|
||||||
|
} else {
|
||||||
|
changes.put(Reseeder.PROP_ONION_RESEED_URL, onionurl);
|
||||||
|
}
|
||||||
|
}
|
||||||
String mode = getJettyString("mode");
|
String mode = getJettyString("mode");
|
||||||
boolean req = "1".equals(mode);
|
boolean req = "1".equals(mode);
|
||||||
boolean disabled = "2".equals(mode);
|
boolean disabled = "2".equals(mode);
|
||||||
|
@ -83,11 +83,11 @@ public class ConfigReseedHelper extends HelperBase {
|
|||||||
return getChecked(Reseeder.PROP_PROXY_AUTH_ENABLE);
|
return getChecked(Reseeder.PROP_PROXY_AUTH_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
public String getSenable() {
|
* public String getSenable() {
|
||||||
return getChecked(Reseeder.PROP_SPROXY_ENABLE);
|
* return getChecked(Reseeder.PROP_SPROXY_ENABLE);
|
||||||
}
|
* }
|
||||||
****/
|
****/
|
||||||
|
|
||||||
/** @since 0.8.9 */
|
/** @since 0.8.9 */
|
||||||
public String getSauth() {
|
public String getSauth() {
|
||||||
@ -95,7 +95,22 @@ public class ConfigReseedHelper extends HelperBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<String> reseedList() {
|
private List<String> reseedList() {
|
||||||
String urls = _context.getProperty(Reseeder.PROP_RESEED_URL, Reseeder.DEFAULT_SEED_URL + ',' + Reseeder.DEFAULT_SSL_SEED_URL);
|
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<String>(16);
|
||||||
|
while (tok.hasMoreTokens()) {
|
||||||
|
String s = tok.nextToken().trim();
|
||||||
|
if (s.length() > 0)
|
||||||
|
URLList.add(s);
|
||||||
|
}
|
||||||
|
return URLList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> onionReseedList() {
|
||||||
|
String urls = _context.getProperty(Reseeder.PROP_ONION_RESEED_URL);
|
||||||
|
if (urls == null)
|
||||||
|
return Collections.emptyList();
|
||||||
StringTokenizer tok = new StringTokenizer(urls, " ,\r\n");
|
StringTokenizer tok = new StringTokenizer(urls, " ,\r\n");
|
||||||
List<String> URLList = new ArrayList<String>(16);
|
List<String> URLList = new ArrayList<String>(16);
|
||||||
while (tok.hasMoreTokens()) {
|
while (tok.hasMoreTokens()) {
|
||||||
@ -118,6 +133,18 @@ public class ConfigReseedHelper extends HelperBase {
|
|||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getOnionReseedURL() {
|
||||||
|
List<String> URLList = onionReseedList();
|
||||||
|
Collections.sort(URLList);
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
for (String s : URLList) {
|
||||||
|
if (buf.length() > 0)
|
||||||
|
buf.append('\n');
|
||||||
|
buf.append(s);
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true only if we have both http and https URLs
|
* @return true only if we have both http and https URLs
|
||||||
* @since 0.9.33
|
* @since 0.9.33
|
||||||
|
@ -154,6 +154,11 @@
|
|||||||
<div class="formaction" id="resetreseed"><input type="submit" name="action" class="reload" value="<%=intl._t("Reset URL list")%>" /></div>
|
<div class="formaction" id="resetreseed"><input type="submit" name="action" class="reload" value="<%=intl._t("Reset URL list")%>" /></div>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
|
|
||||||
|
<tr><td align="right"><b><%=intl._t("Onion Reseed URLs")%>:</b></td>
|
||||||
|
<td><textarea wrap="off" name="onionReseedURL" cols="60" rows="7" spellcheck="false"><jsp:getProperty name="reseedHelper" property="onionReseedURL" /></textarea>
|
||||||
|
<div class="formaction" id="resetreseed"><input type="submit" name="action" class="reload" value="<%=intl._t("Reset Onion URL list")%>" /></div>
|
||||||
|
</td></tr>
|
||||||
|
|
||||||
<% if (reseedHelper.shouldShowHTTPSProxy()) { %>
|
<% if (reseedHelper.shouldShowHTTPSProxy()) { %>
|
||||||
<tr><td align="right"><b><%=intl._t("Proxy type for HTTPS reseed URLs")%>:</b></td>
|
<tr><td align="right"><b><%=intl._t("Proxy type for HTTPS reseed URLs")%>:</b></td>
|
||||||
<td><label><input type="radio" class="optbox" name="pmode" value="" <%=reseedHelper.pmodeChecked(0) %> >
|
<td><label><input type="radio" class="optbox" name="pmode" value="" <%=reseedHelper.pmodeChecked(0) %> >
|
||||||
|
@ -2,7 +2,10 @@ package net.i2p.router.networkdb.reseed;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@ -13,6 +16,7 @@ import net.i2p.util.Addresses;
|
|||||||
import net.i2p.util.AddressType;
|
import net.i2p.util.AddressType;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.SimpleTimer;
|
import net.i2p.util.SimpleTimer;
|
||||||
|
import static net.i2p.socks.SOCKS5Constants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moved from RouterConsoleRunner.java
|
* Moved from RouterConsoleRunner.java
|
||||||
@ -31,15 +35,17 @@ public class ReseedChecker {
|
|||||||
private final RouterContext _context;
|
private final RouterContext _context;
|
||||||
private final Log _log;
|
private final Log _log;
|
||||||
private final AtomicBoolean _inProgress = new AtomicBoolean();
|
private final AtomicBoolean _inProgress = new AtomicBoolean();
|
||||||
|
private volatile String _torHost = "127.0.0.1";
|
||||||
|
private volatile int _torSOCKSPort = 9050;
|
||||||
private volatile String _lastStatus = "";
|
private volatile String _lastStatus = "";
|
||||||
private volatile String _lastError = "";
|
private volatile String _lastError = "";
|
||||||
private volatile boolean _networkLogged;
|
private volatile boolean _networkLogged;
|
||||||
private volatile boolean _alreadyRun;
|
private volatile boolean _alreadyRun;
|
||||||
|
|
||||||
public static final int MINIMUM = 50;
|
public static final int MINIMUM = 50;
|
||||||
private static final long STATUS_CLEAN_TIME = 20*60*1000;
|
private static final long STATUS_CLEAN_TIME = 20 * 60 * 1000;
|
||||||
// if down this long, reseed at startup
|
// if down this long, reseed at startup
|
||||||
private static final long RESEED_MIN_DOWNTIME = 60*24*60*60*1000L;
|
private static final long RESEED_MIN_DOWNTIME = 60 * 24 * 60 * 60 * 1000L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All reseeding must be done through this instance.
|
* All reseeding must be done through this instance.
|
||||||
@ -100,7 +106,8 @@ public class ReseedChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we check the i2p installation directory for a flag telling us not to reseed,
|
// we check the i2p installation directory for a flag telling us not to reseed,
|
||||||
// but also check the home directory for that flag too, since new users installing i2p
|
// but also check the home directory for that flag too, since new users
|
||||||
|
// installing i2p
|
||||||
// don't have an installation directory that they can put the flag in yet.
|
// don't have an installation directory that they can put the flag in yet.
|
||||||
File noReseedFile = new File(new File(System.getProperty("user.home")), ".i2pnoreseed");
|
File noReseedFile = new File(new File(System.getProperty("user.home")), ".i2pnoreseed");
|
||||||
File noReseedFileAlt1 = new File(new File(System.getProperty("user.home")), "noreseed.i2p");
|
File noReseedFileAlt1 = new File(new File(System.getProperty("user.home")), "noreseed.i2p");
|
||||||
@ -162,6 +169,48 @@ public class ReseedChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a reseed from the onion URL pool
|
||||||
|
*
|
||||||
|
* @return true if a reseed was started, false if already in progress
|
||||||
|
* @since 0.9.53
|
||||||
|
*/
|
||||||
|
public boolean requestOnionReseed(){
|
||||||
|
if (!onionReseedsConfigured())
|
||||||
|
return false;
|
||||||
|
if (_inProgress.compareAndSet(false, true)) {
|
||||||
|
_alreadyRun = true;
|
||||||
|
try {
|
||||||
|
Reseeder reseeder = new Reseeder(_context, this);
|
||||||
|
reseeder.requestOnionReseed();
|
||||||
|
return true;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
_log.error("Reseed failed to start", t);
|
||||||
|
done();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("Reseed already in progress");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a list of onion reseeds are configured with i2p.onionReseedURL
|
||||||
|
*
|
||||||
|
* @return true if at least one onion reseed is configured.
|
||||||
|
* @since 0.9.53
|
||||||
|
*/
|
||||||
|
public boolean onionReseedsConfigured() {
|
||||||
|
String url = _context.getProperty(Reseeder.PROP_ONION_RESEED_URL);
|
||||||
|
if (url == null)
|
||||||
|
return false;
|
||||||
|
if (url.length() < 1)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a reseed from a zip or su3 URI.
|
* Start a reseed from a zip or su3 URI.
|
||||||
*
|
*
|
||||||
@ -169,11 +218,169 @@ public class ReseedChecker {
|
|||||||
* @throws IllegalArgumentException if it doesn't end with zip or su3
|
* @throws IllegalArgumentException if it doesn't end with zip or su3
|
||||||
* @since 0.9.19
|
* @since 0.9.19
|
||||||
*/
|
*/
|
||||||
public boolean requestReseed(URI url) throws IllegalArgumentException {
|
public boolean requestReseed(String uri) {
|
||||||
|
URI newURI = URI.create(uri);
|
||||||
|
return requestReseed(newURI, null, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a reseed from a zip or su3 URI.
|
||||||
|
* If Tor is available, use it, otherwise return false.
|
||||||
|
*
|
||||||
|
* @return true if a reseed was started, false if already in progress
|
||||||
|
* @throws IllegalArgumentException if it doesn't end with zip or su3
|
||||||
|
* @since 0.9.52
|
||||||
|
*/
|
||||||
|
public boolean requestOnionReseed(URI uri) {
|
||||||
|
int proxyPort = torSOCKSPort();
|
||||||
|
String proxyHost = torHost();
|
||||||
|
if (testTor(proxyHost, proxyPort)) {
|
||||||
|
return requestReseed(uri, proxyHost, proxyPort);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean testTor() {
|
||||||
|
return testTor(this._torHost, this._torSOCKSPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean testTor(String phost, int pport) { // throws IOException {
|
||||||
|
// test that the socks 5 proxy is there and auth, if any, works
|
||||||
|
Socket s = null;
|
||||||
|
OutputStream out = null;
|
||||||
|
InputStream in = null;
|
||||||
|
String _phost = phost;
|
||||||
|
int _pport = pport;
|
||||||
|
String _puser = ""; //"reseed";
|
||||||
|
String _ppw = "";
|
||||||
|
try {
|
||||||
|
s = new Socket();
|
||||||
|
s.connect(new InetSocketAddress(_phost, _pport), 10 * 1000);
|
||||||
|
out = s.getOutputStream();
|
||||||
|
boolean authAvail = _puser != null && _ppw != null;
|
||||||
|
|
||||||
|
// send the init
|
||||||
|
out.write(SOCKS_VERSION_5);
|
||||||
|
if (authAvail) {
|
||||||
|
out.write(2);
|
||||||
|
out.write(Method.USERNAME_PASSWORD);
|
||||||
|
} else {
|
||||||
|
out.write(1);
|
||||||
|
}
|
||||||
|
out.write(Method.NO_AUTH_REQUIRED);
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
// read init reply
|
||||||
|
in = s.getInputStream();
|
||||||
|
int hisVersion = in.read();
|
||||||
|
if (hisVersion != SOCKS_VERSION_5)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int method = in.read();
|
||||||
|
if (method == Method.NO_AUTH_REQUIRED) {
|
||||||
|
// good
|
||||||
|
} else if (method == Method.USERNAME_PASSWORD) {
|
||||||
|
if (authAvail) {
|
||||||
|
// send the auth
|
||||||
|
out.write(AUTH_VERSION);
|
||||||
|
byte[] user = _puser.getBytes("UTF-8");
|
||||||
|
byte[] pw = _ppw.getBytes("UTF-8");
|
||||||
|
out.write(user.length);
|
||||||
|
out.write(user);
|
||||||
|
out.write(pw.length);
|
||||||
|
out.write(pw);
|
||||||
|
out.flush();
|
||||||
|
// read the auth reply
|
||||||
|
if (in.read() != AUTH_VERSION)
|
||||||
|
return false;
|
||||||
|
if (in.read() != AUTH_SUCCESS)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
if (in != null)
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (out != null)
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (s != null)
|
||||||
|
try {
|
||||||
|
s.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if Tor is running on the host. If it is, return the hostname.
|
||||||
|
*
|
||||||
|
* @return hostname of Tor, or null if Tor is not running
|
||||||
|
* @since 0.9.52
|
||||||
|
*/
|
||||||
|
public String torHost() {
|
||||||
|
if (testTor()) {
|
||||||
|
_torHost = "127.0.0.1";
|
||||||
|
}
|
||||||
|
return _torHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if Tor is running on the host. If it is, return the SOCKSport
|
||||||
|
*
|
||||||
|
* @return SOCKSport of Tor, or -1 if Tor is not running
|
||||||
|
* @since 0.9.52
|
||||||
|
*/
|
||||||
|
public int torSOCKSPort() {
|
||||||
|
if (testTor()) {
|
||||||
|
_torSOCKSPort = 9050;
|
||||||
|
}
|
||||||
|
return _torSOCKSPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a reseed from a zip or su3 URI.
|
||||||
|
*
|
||||||
|
* @return true if a reseed was started, false if already in progress
|
||||||
|
* @throws IllegalArgumentException if it doesn't end with zip or su3
|
||||||
|
* @since 0.9.52
|
||||||
|
*/
|
||||||
|
public boolean requestReseed(URI uri) {
|
||||||
|
return requestReseed(uri, null, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean requestReseed(URI url, String proxyHost, int proxyPort) throws IllegalArgumentException {
|
||||||
|
if (url.getHost().endsWith(".onion")) {
|
||||||
|
if (proxyHost == null && testTor()) {
|
||||||
|
proxyHost = torHost();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Onion reseed requires a proxy host");
|
||||||
|
}
|
||||||
|
if (proxyPort <= 0 && testTor()) {
|
||||||
|
proxyPort = torSOCKSPort();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Onion reseed requires a proxy port");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (_inProgress.compareAndSet(false, true)) {
|
if (_inProgress.compareAndSet(false, true)) {
|
||||||
Reseeder reseeder = new Reseeder(_context, this);
|
Reseeder reseeder = new Reseeder(_context, this);
|
||||||
try {
|
try {
|
||||||
reseeder.requestReseed(url);
|
reseeder.requestReseed(url, proxyHost, proxyPort);
|
||||||
return true;
|
return true;
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (IllegalArgumentException iae) {
|
||||||
if (iae.getMessage() != null)
|
if (iae.getMessage() != null)
|
||||||
@ -217,7 +424,8 @@ public class ReseedChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** .
|
/**
|
||||||
|
* .
|
||||||
* Is a reseed in progress?
|
* Is a reseed in progress?
|
||||||
*
|
*
|
||||||
* @since 0.9
|
* @since 0.9
|
||||||
|
@ -40,7 +40,8 @@ import net.i2p.util.SystemVersion;
|
|||||||
import net.i2p.util.Translate;
|
import net.i2p.util.Translate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moved from ReseedHandler in routerconsole. See ReseedChecker for additional comments.
|
* Moved from ReseedHandler in routerconsole. See ReseedChecker for additional
|
||||||
|
* comments.
|
||||||
*
|
*
|
||||||
* Handler to deal with reseed requests. This will reseed from the URLs
|
* Handler to deal with reseed requests. This will reseed from the URLs
|
||||||
* specified below unless the I2P configuration property "i2p.reseedURL" is
|
* specified below unless the I2P configuration property "i2p.reseedURL" is
|
||||||
@ -54,15 +55,22 @@ public class Reseeder {
|
|||||||
private final Log _log;
|
private final Log _log;
|
||||||
private final ReseedChecker _checker;
|
private final ReseedChecker _checker;
|
||||||
|
|
||||||
// Reject unreasonably big files, because we download into a ByteArrayOutputStream.
|
// Reject unreasonably big files, because we download into a
|
||||||
|
// ByteArrayOutputStream.
|
||||||
private static final long MAX_RESEED_RESPONSE_SIZE = 2 * 1024 * 1024;
|
private static final long MAX_RESEED_RESPONSE_SIZE = 2 * 1024 * 1024;
|
||||||
private static final long MAX_SU3_RESPONSE_SIZE = 1024 * 1024;
|
private static final long MAX_SU3_RESPONSE_SIZE = 1024 * 1024;
|
||||||
/** limit to spend on a single host, to avoid getting stuck on one that is seriously overloaded */
|
/**
|
||||||
|
* limit to spend on a single host, to avoid getting stuck on one that is
|
||||||
|
* seriously overloaded
|
||||||
|
*/
|
||||||
private static final int MAX_TIME_PER_HOST = 7 * 60 * 1000;
|
private static final int MAX_TIME_PER_HOST = 7 * 60 * 1000;
|
||||||
private static final long MAX_FILE_AGE = 30*24*60*60*1000L;
|
private static final long MAX_FILE_AGE = 30 * 24 * 60 * 60 * 1000L;
|
||||||
/** Don't disable this! */
|
/** Don't disable this! */
|
||||||
private static final boolean ENABLE_SU3 = true;
|
private static final boolean ENABLE_SU3 = true;
|
||||||
/** if false, use su3 only, and disable fallback reading directory index and individual dat files */
|
/**
|
||||||
|
* if false, use su3 only, and disable fallback reading directory index and
|
||||||
|
* individual dat files
|
||||||
|
*/
|
||||||
private static final boolean ENABLE_NON_SU3 = false;
|
private static final boolean ENABLE_NON_SU3 = false;
|
||||||
private static final int MIN_RI_WANTED = 100;
|
private static final int MIN_RI_WANTED = 100;
|
||||||
private static final int MIN_RESEED_SERVERS = 2;
|
private static final int MIN_RESEED_SERVERS = 2;
|
||||||
@ -70,22 +78,24 @@ public class Reseeder {
|
|||||||
private static final String NETID_PARAM = "?netid=";
|
private static final String NETID_PARAM = "?netid=";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE - URLs that are in both the standard and SSL groups must use the same hostname,
|
* NOTE - URLs that are in both the standard and SSL groups must use the same
|
||||||
|
* hostname,
|
||||||
* so the reseed process will not download from both.
|
* so the reseed process will not download from both.
|
||||||
* Ports are supported as of 0.9.14.
|
* Ports are supported as of 0.9.14.
|
||||||
*
|
*
|
||||||
* NOTE - Each seedURL must be a directory, it must end with a '/',
|
* NOTE - Each seedURL must be a directory, it must end with a '/',
|
||||||
* it can't end with 'index.html', for example. Both because of how individual file
|
* it can't end with 'index.html', for example. Both because of how individual
|
||||||
|
* file
|
||||||
* URLs are constructed, and because SSLEepGet doesn't follow redirects.
|
* URLs are constructed, and because SSLEepGet doesn't follow redirects.
|
||||||
*/
|
*/
|
||||||
public static final String DEFAULT_SEED_URL =
|
public static final String DEFAULT_SEED_URL =
|
||||||
// Disable due to misconfiguation (ticket #1466)
|
// Disable due to misconfiguation (ticket #1466)
|
||||||
//"http://us.reseed.i2p2.no/" + "," +
|
// "http://us.reseed.i2p2.no/" + "," +
|
||||||
|
|
||||||
// Disabling everything, use SSL
|
// Disabling everything, use SSL
|
||||||
//"http://i2p.mooo.com/netDb/" + "," +
|
// "http://i2p.mooo.com/netDb/" + "," +
|
||||||
//"http://uk.reseed.i2p2.no/" + "," +
|
// "http://uk.reseed.i2p2.no/" + "," +
|
||||||
//"http://netdb.i2p2.no/"; // Only SU3 (v3) support
|
// "http://netdb.i2p2.no/"; // Only SU3 (v3) support
|
||||||
"";
|
"";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -133,8 +143,11 @@ public class Reseeder {
|
|||||||
public static final String PROP_SSL_DISABLE = "router.reseedSSLDisable";
|
public static final String PROP_SSL_DISABLE = "router.reseedSSLDisable";
|
||||||
/** @since 0.8.2 */
|
/** @since 0.8.2 */
|
||||||
public static final String PROP_SSL_REQUIRED = "router.reseedSSLRequired";
|
public static final String PROP_SSL_REQUIRED = "router.reseedSSLRequired";
|
||||||
|
public static final String PROP_ONION_SSL_REQUIRED = "router.onionReseedSSLRequired";
|
||||||
/** @since 0.8.3 */
|
/** @since 0.8.3 */
|
||||||
public static final String PROP_RESEED_URL = "i2p.reseedURL";
|
public static final String PROP_RESEED_URL = "i2p.reseedURL";
|
||||||
|
/** @since 1.7.0 */
|
||||||
|
public static final String PROP_ONION_RESEED_URL = "i2p.onionReseedURL";
|
||||||
/** all these @since 0.8.9 */
|
/** all these @since 0.8.9 */
|
||||||
public static final String PROP_PROXY_USERNAME = "router.reseedProxy.username";
|
public static final String PROP_PROXY_USERNAME = "router.reseedProxy.username";
|
||||||
public static final String PROP_PROXY_PASSWORD = "router.reseedProxy.password";
|
public static final String PROP_PROXY_PASSWORD = "router.reseedProxy.password";
|
||||||
@ -172,15 +185,23 @@ public class Reseeder {
|
|||||||
reseed.start();
|
reseed.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void requestOnionReseed() {
|
||||||
|
ReseedRunner reseedRunner = new ReseedRunner("127.0.0.1", 9050);
|
||||||
|
// set to daemon so it doesn't hang a shutdown
|
||||||
|
Thread reseed = new I2PAppThread(reseedRunner, "OnionReseed", true);
|
||||||
|
reseed.start();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a reseed from a single zip or su3 URL only.
|
* Start a reseed from a single zip or su3 URL only.
|
||||||
|
* Explicitly specify proxy host and port. Use it for both http and https.
|
||||||
* Threaded, nonblocking.
|
* Threaded, nonblocking.
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if it doesn't end with zip or su3
|
* @throws IllegalArgumentException if it doesn't end with zip or su3
|
||||||
* @since 0.9.19
|
* @since 0.9.19
|
||||||
*/
|
*/
|
||||||
void requestReseed(URI url) throws IllegalArgumentException {
|
void requestReseed(URI url, String proxyHost, int proxyPort) {
|
||||||
ReseedRunner reseedRunner = new ReseedRunner(url);
|
ReseedRunner reseedRunner = new ReseedRunner(url, proxyHost, proxyPort);
|
||||||
// set to daemon so it doesn't hang a shutdown
|
// set to daemon so it doesn't hang a shutdown
|
||||||
Thread reseed = new I2PAppThread(reseedRunner, "Reseed", true);
|
Thread reseed = new I2PAppThread(reseedRunner, "Reseed", true);
|
||||||
reseed.start();
|
reseed.start();
|
||||||
@ -213,7 +234,8 @@ public class Reseeder {
|
|||||||
isSU3 = false;
|
isSU3 = false;
|
||||||
else
|
else
|
||||||
throw new IOException("Not a zip or su3 file");
|
throw new IOException("Not a zip or su3 file");
|
||||||
tmp = new File(_context.getTempDir(), "manualreseeds-" + _context.random().nextInt() + (isSU3 ? ".su3" : ".zip"));
|
tmp = new File(_context.getTempDir(),
|
||||||
|
"manualreseeds-" + _context.random().nextInt() + (isSU3 ? ".su3" : ".zip"));
|
||||||
out = new BufferedOutputStream(new SecureFileOutputStream(tmp));
|
out = new BufferedOutputStream(new SecureFileOutputStream(tmp));
|
||||||
out.write(magic);
|
out.write(magic);
|
||||||
DataHelper.copy(in, out);
|
DataHelper.copy(in, out);
|
||||||
@ -236,8 +258,15 @@ public class Reseeder {
|
|||||||
_context.router().eventLog().addEvent(EventLog.RESEED, fetched + " from file");
|
_context.router().eventLog().addEvent(EventLog.RESEED, fetched + " from file");
|
||||||
return fetched;
|
return fetched;
|
||||||
} finally {
|
} finally {
|
||||||
try { in.close(); } catch (IOException ioe) {}
|
try {
|
||||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
in.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
}
|
||||||
|
if (out != null)
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
}
|
||||||
if (tmp != null)
|
if (tmp != null)
|
||||||
tmp.delete();
|
tmp.delete();
|
||||||
}
|
}
|
||||||
@ -274,17 +303,32 @@ public class Reseeder {
|
|||||||
* Start a reseed from the default URL list
|
* Start a reseed from the default URL list
|
||||||
*/
|
*/
|
||||||
public ReseedRunner() {
|
public ReseedRunner() {
|
||||||
this(null);
|
this(null, null, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a reseed from this URL only, or null for trying one or more from the default list.
|
* Create a ReseedRunner which specifies a proxy host and port.
|
||||||
|
* If the proxy is Tor(9050), use it for both HTTP and HTTPS,
|
||||||
|
* if not, defer to the `getProxyType()`
|
||||||
|
*
|
||||||
|
* @param proxyHost hostname or IP address of proxy
|
||||||
|
* @param proxyPort port of proxy
|
||||||
|
*
|
||||||
|
* @since 0.9.53
|
||||||
|
*/
|
||||||
|
public ReseedRunner(String proxyHost, int proxyPort) throws IllegalArgumentException {
|
||||||
|
this(null, proxyHost, proxyPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a reseed from this URL only, or null for trying one or more from the
|
||||||
|
* default list.
|
||||||
*
|
*
|
||||||
* @param url if non-null, must be a zip or su3 URL, NOT a directory
|
* @param url if non-null, must be a zip or su3 URL, NOT a directory
|
||||||
* @throws IllegalArgumentException if it doesn't end with zip or su3
|
* @throws IllegalArgumentException if it doesn't end with zip or su3
|
||||||
* @since 0.9.19
|
* @since 0.9.19
|
||||||
*/
|
*/
|
||||||
public ReseedRunner(URI url) throws IllegalArgumentException {
|
public ReseedRunner(URI url, String proxyHost, int proxyPort) throws IllegalArgumentException {
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
String lc = url.getPath().toLowerCase(Locale.US);
|
String lc = url.getPath().toLowerCase(Locale.US);
|
||||||
if (!(lc.endsWith(".zip") || lc.endsWith(".su3")))
|
if (!(lc.endsWith(".zip") || lc.endsWith(".su3")))
|
||||||
@ -292,33 +336,62 @@ public class Reseeder {
|
|||||||
}
|
}
|
||||||
_url = url;
|
_url = url;
|
||||||
_bandwidths = new ArrayList<Long>(4);
|
_bandwidths = new ArrayList<Long>(4);
|
||||||
|
|
||||||
|
if (_url != null && _url.getHost().endsWith(".onion") || proxyPort == 9050) {
|
||||||
|
_sproxyType = SSLEepGet.ProxyType.SOCKS5;
|
||||||
|
_shouldProxyHTTP = true;
|
||||||
|
_shouldProxySSL = true;
|
||||||
|
if (proxyHost != null && !proxyHost.equals("") && proxyPort > 0) {
|
||||||
|
_proxyHost = proxyHost;
|
||||||
|
_proxyPort = proxyPort;
|
||||||
|
} else {
|
||||||
|
_proxyHost = "127.0.0.1";
|
||||||
|
_proxyPort = 9050;
|
||||||
|
}
|
||||||
|
_sproxyHost = _proxyHost;
|
||||||
|
_sproxyPort = _proxyPort;
|
||||||
|
} else {
|
||||||
|
_sproxyType = getProxyType();
|
||||||
|
_shouldProxyHTTP = _sproxyType != SSLEepGet.ProxyType.NONE;
|
||||||
|
if (proxyPort == 9050) {
|
||||||
|
_shouldProxySSL = true;
|
||||||
|
}else{
|
||||||
|
_shouldProxySSL = _context.getBooleanProperty(PROP_SPROXY_ENABLE);
|
||||||
|
}
|
||||||
|
if (proxyHost != null && !proxyHost.equals("") && proxyPort > 0) {
|
||||||
|
_proxyHost = proxyHost;
|
||||||
|
_proxyPort = proxyPort;
|
||||||
|
_sproxyHost = _proxyHost;
|
||||||
|
_sproxyPort = _proxyPort;
|
||||||
|
} else if (_sproxyType == SSLEepGet.ProxyType.INTERNAL) {
|
||||||
|
_proxyHost = "localhost";
|
||||||
|
_proxyPort = _context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY, 4444);
|
||||||
|
_sproxyHost = "localhost";
|
||||||
|
_sproxyPort = _context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY, 4444);
|
||||||
|
} else if (_sproxyType != SSLEepGet.ProxyType.NONE) {
|
||||||
if (_context.getBooleanProperty(PROP_PROXY_ENABLE)) {
|
if (_context.getBooleanProperty(PROP_PROXY_ENABLE)) {
|
||||||
_proxyHost = _context.getProperty(PROP_PROXY_HOST);
|
_proxyHost = _context.getProperty(PROP_PROXY_HOST);
|
||||||
_proxyPort = _context.getProperty(PROP_PROXY_PORT, -1);
|
_proxyPort = _context.getProperty(PROP_PROXY_PORT, -1);
|
||||||
} else {
|
if (_shouldProxySSL){
|
||||||
_proxyHost = null;
|
|
||||||
_proxyPort = -1;
|
|
||||||
}
|
|
||||||
_shouldProxyHTTP = _proxyHost != null && _proxyHost.length() > 0 && _proxyPort > 0;
|
|
||||||
|
|
||||||
boolean shouldProxySSL = _context.getBooleanProperty(PROP_SPROXY_ENABLE);
|
|
||||||
SSLEepGet.ProxyType sproxyType;
|
|
||||||
if (shouldProxySSL) {
|
|
||||||
sproxyType = getProxyType();
|
|
||||||
if (sproxyType == SSLEepGet.ProxyType.INTERNAL) {
|
|
||||||
_sproxyHost = "localhost";
|
|
||||||
_sproxyPort = _context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY, 4444);
|
|
||||||
} else {
|
|
||||||
_sproxyHost = _context.getProperty(PROP_SPROXY_HOST);
|
_sproxyHost = _context.getProperty(PROP_SPROXY_HOST);
|
||||||
_sproxyPort = _context.getProperty(PROP_SPROXY_PORT, -1);
|
_sproxyPort = _context.getProperty(PROP_SPROXY_PORT, -1);
|
||||||
}
|
}else{
|
||||||
} else {
|
|
||||||
sproxyType = SSLEepGet.ProxyType.NONE;
|
|
||||||
_sproxyHost = null;
|
_sproxyHost = null;
|
||||||
_sproxyPort = -1;
|
_sproxyPort = -1;
|
||||||
}
|
}
|
||||||
_shouldProxySSL = shouldProxySSL && _sproxyHost != null && _sproxyHost.length() > 0 && _sproxyPort > 0;
|
} else {
|
||||||
_sproxyType = _shouldProxySSL ? sproxyType : SSLEepGet.ProxyType.NONE;
|
_proxyHost = null;
|
||||||
|
_proxyPort = -1;
|
||||||
|
_sproxyHost = null;
|
||||||
|
_sproxyPort = -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_proxyHost = null;
|
||||||
|
_proxyPort = -1;
|
||||||
|
_sproxyHost = null;
|
||||||
|
_sproxyPort = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -354,9 +427,13 @@ public class Reseeder {
|
|||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Must end with .zip or .su3");
|
throw new IllegalArgumentException("Must end with .zip or .su3");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (_checker.onionReseedsConfigured()){
|
||||||
|
total = reseedOnion(false);
|
||||||
} else {
|
} else {
|
||||||
total = reseed(false);
|
total = reseed(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (total >= 20) {
|
if (total >= 20) {
|
||||||
String s = ngettext("Reseed successful, fetched {0} router info",
|
String s = ngettext("Reseed successful, fetched {0} router info",
|
||||||
"Reseed successful, fetched {0} router infos", total);
|
"Reseed successful, fetched {0} router infos", total);
|
||||||
@ -382,7 +459,8 @@ public class Reseeder {
|
|||||||
System.out.println("Consider enabling a proxy for https on the reseed configuration page");
|
System.out.println("Consider enabling a proxy for https on the reseed configuration page");
|
||||||
} else {
|
} else {
|
||||||
if (_proxyHost != null && _proxyPort > 0)
|
if (_proxyHost != null && _proxyPort > 0)
|
||||||
System.out.println("Check HTTP proxy setting - host: " + _proxyHost + " port: " + _proxyPort);
|
System.out
|
||||||
|
.println("Check HTTP proxy setting - host: " + _proxyHost + " port: " + _proxyPort);
|
||||||
else
|
else
|
||||||
System.out.println("Consider enabling an HTTP proxy on the reseed configuration page");
|
System.out.println("Consider enabling an HTTP proxy on the reseed configuration page");
|
||||||
}
|
}
|
||||||
@ -390,13 +468,14 @@ public class Reseeder {
|
|||||||
String old = _checker.getError();
|
String old = _checker.getError();
|
||||||
_checker.setError(_t("Reseed failed.") + ' ' +
|
_checker.setError(_t("Reseed failed.") + ' ' +
|
||||||
_t("See {0} for help.",
|
_t("See {0} for help.",
|
||||||
"<a target=\"_top\" href=\"/configreseed\">" + _t("reseed configuration page") + "</a>") +
|
"<a target=\"_top\" href=\"/configreseed\">" + _t("reseed configuration page") + "</a>")
|
||||||
|
+
|
||||||
"<br>" + old);
|
"<br>" + old);
|
||||||
_checker.setStatus("");
|
_checker.setStatus("");
|
||||||
}
|
}
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
// ReseedChecker will set timer to clean up
|
// ReseedChecker will set timer to clean up
|
||||||
//_checker.setStatus("");
|
// _checker.setStatus("");
|
||||||
if (total > 0)
|
if (total > 0)
|
||||||
_context.router().eventLog().addEvent(EventLog.RESEED, Integer.toString(total));
|
_context.router().eventLog().addEvent(EventLog.RESEED, Integer.toString(total));
|
||||||
}
|
}
|
||||||
@ -418,7 +497,8 @@ public class Reseeder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EepGet status listeners
|
// EepGet status listeners
|
||||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
|
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt,
|
||||||
|
int numRetries, Exception cause) {
|
||||||
// Since readURL() runs an EepGet with 0 retries,
|
// Since readURL() runs an EepGet with 0 retries,
|
||||||
// we can report errors with attemptFailed() instead of transferFailed().
|
// we can report errors with attemptFailed() instead of transferFailed().
|
||||||
// It has the benefit of providing cause of failure, which helps resolve issues.
|
// It has the benefit of providing cause of failure, which helps resolve issues.
|
||||||
@ -430,9 +510,16 @@ public class Reseeder {
|
|||||||
_checker.setError(DataHelper.escapeHTML(cause.getMessage()));
|
_checker.setError(DataHelper.escapeHTML(cause.getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {}
|
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred,
|
||||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {}
|
long bytesRemaining, String url) {
|
||||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {}
|
}
|
||||||
|
|
||||||
|
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url,
|
||||||
|
String outputFile, boolean notModified) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the Date header as a backup time source
|
* Use the Date header as a backup time source
|
||||||
@ -458,7 +545,8 @@ public class Reseeder {
|
|||||||
_log.warn("Reseed adjusting clock by " +
|
_log.warn("Reseed adjusting clock by " +
|
||||||
DataHelper.formatDuration(Math.abs(offset)));
|
DataHelper.formatDuration(Math.abs(offset)));
|
||||||
} else {
|
} else {
|
||||||
// No peers or NTP yet, this is probably better than the peer average will be for a while
|
// No peers or NTP yet, this is probably better than the peer average will be
|
||||||
|
// for a while
|
||||||
// default stratum - 1, so the peer average is a worse stratum
|
// default stratum - 1, so the peer average is a worse stratum
|
||||||
_context.clock().setNow(now, RouterClock.DEFAULT_STRATUM - 1);
|
_context.clock().setNow(now, RouterClock.DEFAULT_STRATUM - 1);
|
||||||
_log.logAlways(Log.WARN, "NTP failure, Reseed adjusting clock by " +
|
_log.logAlways(Log.WARN, "NTP failure, Reseed adjusting clock by " +
|
||||||
@ -482,7 +570,8 @@ public class Reseeder {
|
|||||||
* the routerInfo-*.dat files from the specified URL (or the default) and
|
* the routerInfo-*.dat files from the specified URL (or the default) and
|
||||||
* save them into this router's netDb dir.
|
* save them into this router's netDb dir.
|
||||||
*
|
*
|
||||||
* - If list specified in the properties, use it randomly, without regard to http/https
|
* - If list specified in the properties, use it randomly, without regard to
|
||||||
|
* http/https
|
||||||
* - If SSL not disabled, use the https randomly then
|
* - If SSL not disabled, use the https randomly then
|
||||||
* the http randomly
|
* the http randomly
|
||||||
* - Otherwise just the http randomly.
|
* - Otherwise just the http randomly.
|
||||||
@ -491,12 +580,36 @@ public class Reseeder {
|
|||||||
* @return count of routerinfos successfully fetched, or -1 if no valid URLs
|
* @return count of routerinfos successfully fetched, or -1 if no valid URLs
|
||||||
*/
|
*/
|
||||||
private int reseed(boolean echoStatus) {
|
private int reseed(boolean echoStatus) {
|
||||||
List<URI> URLList = new ArrayList<URI>();
|
|
||||||
String URLs = _context.getProperty(PROP_RESEED_URL);
|
|
||||||
boolean defaulted = URLs == null;
|
|
||||||
boolean SSLDisable = _context.getBooleanProperty(PROP_SSL_DISABLE);
|
boolean SSLDisable = _context.getBooleanProperty(PROP_SSL_DISABLE);
|
||||||
boolean SSLRequired = _context.getBooleanPropertyDefaultTrue(PROP_SSL_REQUIRED);
|
boolean SSLRequired = _context.getBooleanPropertyDefaultTrue(PROP_SSL_REQUIRED);
|
||||||
|
return reseed(echoStatus, PROP_RESEED_URL, SSLDisable, SSLRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Onion Reseed has been requested, so lets go ahead and do it. Fetch all of
|
||||||
|
* the routerInfo-*.dat files from the specified onion URLs from the special
|
||||||
|
* onion-only list
|
||||||
|
* (or the default) and save them into this router's netDb dir.
|
||||||
|
*
|
||||||
|
* - SSL is enabled but not required for .onion URLs in this list.
|
||||||
|
* - set onionReseedSSLRequired=true to require SSL for onion reseed
|
||||||
|
*
|
||||||
|
* @param echoStatus apparently always false
|
||||||
|
* @return count of routerinfos successfully fetched, or -1 if no valid URLs
|
||||||
|
*/
|
||||||
|
private int reseedOnion(boolean echoStatus) {
|
||||||
|
boolean SSLDisable = _context.getBooleanProperty(PROP_SSL_DISABLE);
|
||||||
|
boolean SSLRequired = _context.getBooleanProperty(PROP_ONION_SSL_REQUIRED);
|
||||||
|
String urls = _context.getProperty(PROP_ONION_RESEED_URL);
|
||||||
|
if (urls == null)
|
||||||
|
return 0;
|
||||||
|
return reseed(echoStatus, PROP_ONION_RESEED_URL, SSLDisable, SSLRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int reseed(boolean echoStatus, String urlProp, boolean SSLRequired, boolean SSLDisable) {
|
||||||
|
List<URI> URLList = new ArrayList<URI>();
|
||||||
|
String URLs = _context.getProperty(urlProp);
|
||||||
|
boolean defaulted = URLs == null;
|
||||||
if (defaulted) {
|
if (defaulted) {
|
||||||
if (SSLDisable)
|
if (SSLDisable)
|
||||||
URLs = DEFAULT_SEED_URL;
|
URLs = DEFAULT_SEED_URL;
|
||||||
@ -509,7 +622,8 @@ public class Reseeder {
|
|||||||
u = u + '/';
|
u = u + '/';
|
||||||
try {
|
try {
|
||||||
URLList.add(new URI(u));
|
URLList.add(new URI(u));
|
||||||
} catch (URISyntaxException mue) {}
|
} catch (URISyntaxException mue) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Collections.shuffle(URLList, _context.random());
|
Collections.shuffle(URLList, _context.random());
|
||||||
if (!SSLDisable && !SSLRequired) {
|
if (!SSLDisable && !SSLRequired) {
|
||||||
@ -522,7 +636,8 @@ public class Reseeder {
|
|||||||
u = u + '/';
|
u = u + '/';
|
||||||
try {
|
try {
|
||||||
URLList2.add(new URI(u));
|
URLList2.add(new URI(u));
|
||||||
} catch (URISyntaxException mue) {}
|
} catch (URISyntaxException mue) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Collections.shuffle(URLList2, _context.random());
|
Collections.shuffle(URLList2, _context.random());
|
||||||
URLList.addAll(URLList2);
|
URLList.addAll(URLList2);
|
||||||
@ -541,17 +656,19 @@ public class Reseeder {
|
|||||||
if (u.startsWith("https")) {
|
if (u.startsWith("https")) {
|
||||||
try {
|
try {
|
||||||
SSLList.add(new URI(u));
|
SSLList.add(new URI(u));
|
||||||
} catch (URISyntaxException mue) {}
|
} catch (URISyntaxException mue) {
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
nonSSLList.add(new URI(u));
|
nonSSLList.add(new URI(u));
|
||||||
} catch (URISyntaxException mue) {}
|
} catch (URISyntaxException mue) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// shuffle lists
|
// shuffle lists
|
||||||
// depending on preferences, add lists to URLList
|
// depending on preferences, add lists to URLList
|
||||||
if (!SSLDisable) {
|
if (!SSLDisable) {
|
||||||
Collections.shuffle(SSLList,_context.random());
|
Collections.shuffle(SSLList, _context.random());
|
||||||
URLList.addAll(SSLList);
|
URLList.addAll(SSLList);
|
||||||
}
|
}
|
||||||
if (SSLDisable || !SSLRequired) {
|
if (SSLDisable || !SSLRequired) {
|
||||||
@ -563,7 +680,8 @@ public class Reseeder {
|
|||||||
try {
|
try {
|
||||||
URLList.remove(new URI("https://download.xxlspeed.com/"));
|
URLList.remove(new URI("https://download.xxlspeed.com/"));
|
||||||
URLList.remove(new URI("https://netdb.i2p2.no/"));
|
URLList.remove(new URI("https://netdb.i2p2.no/"));
|
||||||
} catch (URISyntaxException mue) {}
|
} catch (URISyntaxException mue) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (URLList.isEmpty()) {
|
if (URLList.isEmpty()) {
|
||||||
System.out.println("No valid reseed URLs");
|
System.out.println("No valid reseed URLs");
|
||||||
@ -596,7 +714,8 @@ public class Reseeder {
|
|||||||
if (ENABLE_SU3) {
|
if (ENABLE_SU3) {
|
||||||
try {
|
try {
|
||||||
dl = reseedSU3(new URI(url.toString() + SU3_FILENAME + query), echoStatus);
|
dl = reseedSU3(new URI(url.toString() + SU3_FILENAME + query), echoStatus);
|
||||||
} catch (URISyntaxException mue) {}
|
} catch (URISyntaxException mue) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ENABLE_NON_SU3) {
|
if (ENABLE_NON_SU3) {
|
||||||
if (dl <= 0)
|
if (dl <= 0)
|
||||||
@ -609,7 +728,7 @@ public class Reseeder {
|
|||||||
if (total >= MIN_RI_WANTED && fetched_reseed_servers >= MIN_RESEED_SERVERS)
|
if (total >= MIN_RI_WANTED && fetched_reseed_servers >= MIN_RESEED_SERVERS)
|
||||||
break;
|
break;
|
||||||
// remove alternate versions if we haven't tried them yet
|
// remove alternate versions if we haven't tried them yet
|
||||||
for (int j = i + 1; j < URLList.size(); ) {
|
for (int j = i + 1; j < URLList.size();) {
|
||||||
if (url.getHost().equals(URLList.get(j).getHost()))
|
if (url.getHost().equals(URLList.get(j).getHost()))
|
||||||
URLList.remove(j);
|
URLList.remove(j);
|
||||||
else
|
else
|
||||||
@ -701,11 +820,12 @@ public class Reseeder {
|
|||||||
int fetched = 0;
|
int fetched = 0;
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
// 200 max from one URL
|
// 200 max from one URL
|
||||||
for (Iterator<String> iter = urlList.iterator();
|
for (Iterator<String> iter = urlList.iterator(); iter.hasNext() && fetched < 200
|
||||||
iter.hasNext() && fetched < 200 && System.currentTimeMillis() < timeLimit; ) {
|
&& System.currentTimeMillis() < timeLimit;) {
|
||||||
try {
|
try {
|
||||||
_checker.setStatus(
|
_checker.setStatus(
|
||||||
_t("Reseeding: fetching router info from seed URL ({0} successful, {1} errors).", fetched, errors));
|
_t("Reseeding: fetching router info from seed URL ({0} successful, {1} errors).",
|
||||||
|
fetched, errors));
|
||||||
|
|
||||||
if (!fetchSeed(seedURL.toString(), iter.next()))
|
if (!fetchSeed(seedURL.toString(), iter.next()))
|
||||||
continue;
|
continue;
|
||||||
@ -825,11 +945,11 @@ public class Reseeder {
|
|||||||
}
|
}
|
||||||
_checker.setStatus(
|
_checker.setStatus(
|
||||||
_t("Reseeding: fetching router info from seed URL ({0} successful, {1} errors).", fetched, errors));
|
_t("Reseeding: fetching router info from seed URL ({0} successful, {1} errors).", fetched, errors));
|
||||||
System.err.println("Reseed got " + fetched + " router infos " + getDisplayString(seedURL) + " with " + errors + " errors");
|
System.err.println("Reseed got " + fetched + " router infos " + getDisplayString(seedURL) + " with "
|
||||||
|
+ errors + " errors");
|
||||||
return fetched;
|
return fetched;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 2 ints: number successful and number of errors
|
* @return 2 ints: number successful and number of errors
|
||||||
* @since 0.9.19 pulled from reseedSU3
|
* @since 0.9.19 pulled from reseedSU3
|
||||||
@ -855,7 +975,8 @@ public class Reseeder {
|
|||||||
if (ver < _context.clock().now() - MAX_FILE_AGE)
|
if (ver < _context.clock().now() - MAX_FILE_AGE)
|
||||||
throw new IOException("su3 file too old");
|
throw new IOException("su3 file too old");
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException nfe) {}
|
} catch (NumberFormatException nfe) {
|
||||||
|
}
|
||||||
|
|
||||||
int[] stats = extractZip(zip);
|
int[] stats = extractZip(zip);
|
||||||
fetched = stats[0];
|
fetched = stats[0];
|
||||||
@ -903,12 +1024,12 @@ public class Reseeder {
|
|||||||
netDbDir.mkdirs();
|
netDbDir.mkdirs();
|
||||||
|
|
||||||
// 400 max from one URL
|
// 400 max from one URL
|
||||||
for (Iterator<File> iter = fList.iterator(); iter.hasNext() && fetched < 400; ) {
|
for (Iterator<File> iter = fList.iterator(); iter.hasNext() && fetched < 400;) {
|
||||||
File f = iter.next();
|
File f = iter.next();
|
||||||
String name = f.getName();
|
String name = f.getName();
|
||||||
if (name.length() != ROUTERINFO_PREFIX.length() + 44 + ROUTERINFO_SUFFIX.length() ||
|
if (name.length() != ROUTERINFO_PREFIX.length() + 44 + ROUTERINFO_SUFFIX.length() ||
|
||||||
name.equals(ourB64) ||
|
name.equals(ourB64) ||
|
||||||
f.length() > 10*1024 ||
|
f.length() > 10 * 1024 ||
|
||||||
f.lastModified() < minTime ||
|
f.lastModified() < minTime ||
|
||||||
!name.startsWith(ROUTERINFO_PREFIX) ||
|
!name.startsWith(ROUTERINFO_PREFIX) ||
|
||||||
!name.endsWith(ROUTERINFO_SUFFIX) ||
|
!name.endsWith(ROUTERINFO_SUFFIX) ||
|
||||||
@ -945,9 +1066,11 @@ public class Reseeder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Always throws an exception if something fails.
|
* Always throws an exception if something fails.
|
||||||
* We do NOT validate the received data here - that is done in PersistentDataStore
|
* We do NOT validate the received data here - that is done in
|
||||||
|
* PersistentDataStore
|
||||||
*
|
*
|
||||||
* @param peer The Base64 hash, may include % encoding. It is decoded and validated here.
|
* @param peer The Base64 hash, may include % encoding. It is decoded and
|
||||||
|
* validated here.
|
||||||
* @return true on success, false if skipped
|
* @return true on success, false if skipped
|
||||||
*/
|
*/
|
||||||
private boolean fetchSeed(String seedURL, String peer) throws IOException, URISyntaxException {
|
private boolean fetchSeed(String seedURL, String peer) throws IOException, URISyntaxException {
|
||||||
@ -965,7 +1088,8 @@ public class Reseeder {
|
|||||||
if (ourHash != null && DataHelper.eq(hash, ourHash.getData()))
|
if (ourHash != null && DataHelper.eq(hash, ourHash.getData()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
URI url = new URI(seedURL + (seedURL.endsWith("/") ? "" : "/") + ROUTERINFO_PREFIX + peer + ROUTERINFO_SUFFIX);
|
URI url = new URI(
|
||||||
|
seedURL + (seedURL.endsWith("/") ? "" : "/") + ROUTERINFO_PREFIX + peer + ROUTERINFO_SUFFIX);
|
||||||
|
|
||||||
byte data[] = readURL(url);
|
byte data[] = readURL(url);
|
||||||
if (data == null || data.length <= 0)
|
if (data == null || data.length <= 0)
|
||||||
@ -975,7 +1099,7 @@ public class Reseeder {
|
|||||||
|
|
||||||
/** @return null on error */
|
/** @return null on error */
|
||||||
private byte[] readURL(URI url) throws IOException {
|
private byte[] readURL(URI url) throws IOException {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024);
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(4 * 1024);
|
||||||
EepGet get;
|
EepGet get;
|
||||||
boolean ssl = "https".equals(url.getScheme());
|
boolean ssl = "https".equals(url.getScheme());
|
||||||
if (ssl) {
|
if (ssl) {
|
||||||
@ -1004,7 +1128,8 @@ public class Reseeder {
|
|||||||
get.addAuthorization(user, pass);
|
get.addAuthorization(user, pass);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Do a (probably) non-proxied eepget into our ByteArrayOutputStream with 0 retries
|
// Do a (probably) non-proxied eepget into our ByteArrayOutputStream with 0
|
||||||
|
// retries
|
||||||
get = new EepGet(_context, _shouldProxyHTTP, _proxyHost, _proxyPort, 0, 0, MAX_RESEED_RESPONSE_SIZE,
|
get = new EepGet(_context, _shouldProxyHTTP, _proxyHost, _proxyPort, 0, 0, MAX_RESEED_RESPONSE_SIZE,
|
||||||
null, baos, url.toString(), false, null, null);
|
null, baos, url.toString(), false, null, null);
|
||||||
if (_shouldProxyHTTP && _context.getBooleanProperty(PROP_PROXY_AUTH_ENABLE)) {
|
if (_shouldProxyHTTP && _context.getBooleanProperty(PROP_PROXY_AUTH_ENABLE)) {
|
||||||
@ -1096,7 +1221,7 @@ public class Reseeder {
|
|||||||
File file = new File(netDbDir, ROUTERINFO_PREFIX + name + ROUTERINFO_SUFFIX);
|
File file = new File(netDbDir, ROUTERINFO_PREFIX + name + ROUTERINFO_SUFFIX);
|
||||||
// don't overwrite recent file
|
// don't overwrite recent file
|
||||||
// TODO: even better would be to compare to last-mod date from eepget
|
// TODO: even better would be to compare to last-mod date from eepget
|
||||||
if (file.exists() && file.lastModified() > _context.clock().now() - 60*60*1000) {
|
if (file.exists() && file.lastModified() > _context.clock().now() - 60 * 60 * 1000) {
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Skipping RI, ours is recent: " + file);
|
_log.info("Skipping RI, ours is recent: " + file);
|
||||||
return false;
|
return false;
|
||||||
@ -1109,8 +1234,10 @@ public class Reseeder {
|
|||||||
_log.info("Saved RI (" + data.length + " bytes) to " + file);
|
_log.info("Saved RI (" + data.length + " bytes) to " + file);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (fos != null) fos.close();
|
if (fos != null)
|
||||||
} catch (IOException ioe) {}
|
fos.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1182,7 +1309,7 @@ public class Reseeder {
|
|||||||
* @since 0.9.33
|
* @since 0.9.33
|
||||||
*/
|
*/
|
||||||
private String getDisplayString(SSLEepGet.ProxyType type) {
|
private String getDisplayString(SSLEepGet.ProxyType type) {
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case HTTP:
|
case HTTP:
|
||||||
return "HTTPS";
|
return "HTTPS";
|
||||||
case SOCKS4:
|
case SOCKS4:
|
||||||
@ -1219,15 +1346,16 @@ public class Reseeder {
|
|||||||
return Translate.getString(n, s, p, _context, BUNDLE_NAME);
|
return Translate.getString(n, s, p, _context, BUNDLE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******
|
/******
|
||||||
public static void main(String args[]) {
|
* public static void main(String args[]) {
|
||||||
if ( (args != null) && (args.length == 1) && (!Boolean.parseBoolean(args[0])) ) {
|
* if ( (args != null) && (args.length == 1) && (!Boolean.parseBoolean(args[0]))
|
||||||
System.out.println("Not reseeding, as requested");
|
* ) {
|
||||||
return; // not reseeding on request
|
* System.out.println("Not reseeding, as requested");
|
||||||
}
|
* return; // not reseeding on request
|
||||||
System.out.println("Reseeding");
|
* }
|
||||||
Reseeder reseedHandler = new Reseeder();
|
* System.out.println("Reseeding");
|
||||||
reseedHandler.requestReseed();
|
* Reseeder reseedHandler = new Reseeder();
|
||||||
}
|
* reseedHandler.requestReseed();
|
||||||
******/
|
* }
|
||||||
|
******/
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user