Changeset 59348f8d


Ignore:
Timestamp:
Mar 19, 2015 11:17:18 PM (6 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
a3802d4
Parents:
8742a66
Message:

Reseed:

  • Add form to manually reseed from zip or su3 URL (result status not yet working)
  • Add form to manually reseed from local zip or su3 file (not yet working, needs multipart/form-date moved from susimail)
  • Add form to create reseed zip file to share (working)
  • Backend support and refactoring in reseed code
Files:
3 added
6 edited

Legend:

Unmodified
Added
Removed
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHandler.java

    r8742a66 r59348f8d  
    11package net.i2p.router.web;
    22
     3import java.io.ByteArrayInputStream;
     4import java.io.InputStream;
     5import java.io.IOException;
     6import java.net.URL;
     7import java.net.MalformedURLException;
    38import java.util.ArrayList;
    49import java.util.HashMap;
     
    611import java.util.Map;
    712
     13import net.i2p.data.DataHelper;
    814import net.i2p.router.networkdb.reseed.Reseeder;
    915
     
    2632                addFormNotice(_("Starting reseed process"));
    2733            }
    28             return;
    29         }
    30         if (_action.equals(_("Save changes"))) {
     34        } else if (_action.equals(_("Reseed from URL"))) {
     35            String val = getJettyString("url");
     36            if (val != null)
     37                val = val.trim();
     38            if (val == null || val.length() == 0) {
     39                addFormError(_("You must enter a URL"));
     40                return;
     41            }
     42            URL url;
     43            try {
     44                url = new URL(val);
     45            } catch (MalformedURLException mue) {
     46                addFormError(_("Bad URL {0}", val));
     47                return;
     48            }
     49            try {
     50                if (!_context.netDb().reseedChecker().requestReseed(url)) {
     51                    addFormError(_("Reseeding is already in progress"));
     52                } else {
     53                    // wait a while for completion but not forever
     54                    for (int i = 0; i < 20; i++) {
     55                        try {
     56                            Thread.sleep(1000);
     57                        } catch (InterruptedException ie) {}
     58                        if (!_context.netDb().reseedChecker().inProgress()) {
     59                            String status = _context.netDb().reseedChecker().getStatus();
     60                            if (status.length() > 0)
     61                                addFormNotice(status);
     62                            else
     63                                addFormNotice(_("Ressed complete, check summary bar for status"));
     64                            return;
     65                        }
     66                    }
     67                    if (_context.netDb().reseedChecker().inProgress()) {
     68                        String status = _context.netDb().reseedChecker().getStatus();
     69                        if (status.length() > 0)
     70                            addFormNotice(status);
     71                        else
     72                            addFormNotice(_("Ressed in progress, check summary bar for status"));
     73                    }
     74                }
     75            } catch (IllegalArgumentException iae) {
     76                addFormError(_("Bad URL {0}", val) + " - " + iae.getMessage());
     77            }
     78        } else if (_action.equals(_("Reseed from file"))) {
     79            //////// FIXME multipart
     80            String val = getJettyString("file");
     81            if (val == null || val.length() == 0) {
     82                addFormError(_("You must enter a file"));
     83                return;
     84            }
     85            ByteArrayInputStream bais = new ByteArrayInputStream(DataHelper.getASCII(val));
     86            try {
     87                int count = _context.netDb().reseedChecker().requestReseed(bais);
     88                if (count <= 0) {
     89                    addFormError(_("Reseed from file failed"));
     90                } else {
     91                    addFormNotice(ngettext("Reseed successful, loaded {0} router info from file",
     92                                           "Reseed successful, loaded {0} router infos from file",
     93                                           count));
     94                }
     95            } catch (IOException ioe) {
     96                addFormError(_("Reseed from file failed") + " - " + ioe);
     97            }
     98        } else if (_action.equals(_("Save changes"))) {
    3199            saveChanges();
    32             return;
    33100        }
    34101        //addFormError(_("Unsupported") + ' ' + _action + '.');
     
    85152            addFormError(_("Error saving the configuration (applied but not saved) - please see the error logs"));
    86153    }
     154
     155    /** translate (ngettext) @since 0.9.19 */
     156    public String ngettext(String s, String p, int n) {
     157        return Messages.getString(n, s, p, _context);
     158    }
    87159}
  • apps/routerconsole/jsp/configreseed.jsp

    r8742a66 r59348f8d  
    2020<jsp:useBean class="net.i2p.router.web.ConfigReseedHandler" id="formhandler" scope="request" />
    2121<%@include file="formhandler.jsi" %>
     22
    2223<div class="configure"><form action="" method="POST">
     24<input type="hidden" name="nonce" value="<%=pageNonce%>" >
     25<h3><%=intl._("Manual Reseed from URL")%></h3>
     26<p><%=intl._("Enter zip or su3 URL")%> :
     27<input name="url" type="text" size="60" value="" />
     28</p>
     29<div class="formaction">
     30<input type="submit" name="action" class="download" value="<%=intl._("Reseed from URL")%>" />
     31</div></form></div>
     32
     33<div class="configure">
     34<form action="" method="POST" enctype="multipart/form-data" >
     35<input type="hidden" name="nonce" value="<%=pageNonce%>" >
     36<h3><%=intl._("Manual Reseed from File")%></h3>
     37<p><%=intl._("Select zip or su3 file")%> :
     38<input name="file" type="file" value="" />
     39</p>
     40<div class="formaction">
     41<input type="submit" name="action" class="download" value="<%=intl._("Reseed from file")%>" />
     42</div></form></div>
     43
     44<div class="configure">
     45<form action="/createreseed" method="GET">
     46<h3><%=intl._("Create Reseed File")%></h3>
     47<p><%=intl._("Create a new reseed zip file you may share for others to reseed manually.")%>
     48</p>
     49<div class="formaction">
     50<input type="submit" name="action" class="go" value="<%=intl._("Create reseed file")%>" />
     51</div></form></div>
     52
     53<div class="configure">
     54<form action="" method="POST">
    2355<input type="hidden" name="nonce" value="<%=pageNonce%>" >
    2456<h3><%=intl._("Reseeding Configuration")%></h3>
     
    72104
    73105</table></div>
    74 <hr><div class="formaction">
     106<div class="formaction">
    75107<input type="submit" class="cancel" name="foo" value="<%=intl._("Cancel")%>" />
    76108<input type="submit" name="action" class="download" value="<%=intl._("Save changes and reseed now")%>" />
  • history.txt

    r8742a66 r59348f8d  
     12015-03-19 zzz
     2 * Reseed:
     3  - Add form to manually reseed from zip or su3 URL
     4  - Add form to manually reseed from local zip or su3 file
     5  - Add form to create reseed zip file to share
     6  - Backend support and refactoring in reseed code
     7
    182015-03-18 zzz
    29 * NetDB:
     
    512  - Don't encrypt RI lookups when overloaded
    613  - Don't explore when overloaded
     14  - Don't publish non-ff RI on exit if we are coming right back
     15 * Router: Allow disabling the setting of some System properties, for embedded applications
     16 * StatisticsManager: Publish dummy LS count if we just started
     17 * Streaming: Reduce min RTO again
    718 * Tunnels: Drop instead of reject requests on high job lag
    819 * UPnP: Update to cyberlink 3.0
  • router/java/src/net/i2p/router/RouterVersion.java

    r8742a66 r59348f8d  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 6;
     21    public final static long BUILD = 7;
    2222
    2323    /** for example "-test" */
  • router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java

    r8742a66 r59348f8d  
    22
    33import java.io.File;
     4import java.io.InputStream;
     5import java.io.IOException;
     6import java.net.URL;
    47import java.util.concurrent.atomic.AtomicBoolean;
    58
     
    108111
    109112    /**
     113     *  Start a reseed from a zip or su3 URI.
     114     *
     115     *  @return true if a reseed was started, false if already in progress
     116     *  @throws IllegalArgumentException if it doesn't end with zip or su3
     117     *  @since 0.9.19
     118     */
     119    public boolean requestReseed(URL url) throws IllegalArgumentException {
     120        if (_inProgress.compareAndSet(false, true)) {
     121            Reseeder reseeder = new Reseeder(_context, this);
     122            try {
     123                reseeder.requestReseed(url);
     124                return true;
     125            } catch (IllegalArgumentException iae) {
     126                done();
     127                throw iae;
     128            } catch (Throwable t) {
     129                _log.error("Reseed failed to start", t);
     130                done();
     131                return false;
     132            }
     133        } else {
     134            if (_log.shouldLog(Log.WARN))
     135                _log.warn("Reseed already in progress");
     136            return false;
     137        }
     138    }
     139
     140    /**
     141     *  Reseed from a zip or su3 input stream. Blocking.
     142     *
     143     *  @return true if a reseed was started, false if already in progress
     144     *  @throws IOException if already in progress or on most other errors
     145     *  @since 0.9.19
     146     */
     147    public int requestReseed(InputStream in) throws IOException {
     148        // don't really need to check for in progress here
     149        if (_inProgress.compareAndSet(false, true)) {
     150            try {
     151                Reseeder reseeder = new Reseeder(_context, this);
     152                return reseeder.requestReseed(in);
     153            } finally {
     154                done();
     155            }
     156        } else {
     157            throw new IOException("Reseed already in progress");
     158        }
     159    }
     160
     161    /**         .
    110162     *  Is a reseed in progress?
    111163     *
  • router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java

    r8742a66 r59348f8d  
    11package net.i2p.router.networkdb.reseed;
    22
     3import java.io.BufferedOutputStream;
    34import java.io.ByteArrayOutputStream;
    45import java.io.File;
    56import java.io.FileOutputStream;
     7import java.io.InputStream;
    68import java.io.IOException;
     9import java.io.OutputStream;
    710import java.net.MalformedURLException;
    811import java.net.URI;
     
    131134    }
    132135
     136    /**
     137     *  Start a reseed using the default reseed URLs.
     138     *  Supports su3 and directories.
     139     *  Threaded, nonblocking.
     140     */
    133141    void requestReseed() {
    134142        ReseedRunner reseedRunner = new ReseedRunner();
     
    136144        Thread reseed = new I2PAppThread(reseedRunner, "Reseed", true);
    137145        reseed.start();
     146    }
     147
     148    /**
     149     *  Start a reseed from a single zip or su3 URL only.
     150     *  Threaded, nonblocking.
     151     *
     152     *  @throws IllegalArgumentException if it doesn't end with zip or su3
     153     *  @since 0.9.19
     154     */
     155    void requestReseed(URL url) throws IllegalArgumentException {
     156        ReseedRunner reseedRunner = new ReseedRunner(url);
     157        // set to daemon so it doesn't hang a shutdown
     158        Thread reseed = new I2PAppThread(reseedRunner, "Reseed", true);
     159        reseed.start();
     160    }
     161
     162    /**
     163     *  Start a reseed from a zip or su3 input stream.
     164     *  Blocking, inline. Should be fast.
     165     *  This will close the stream.
     166     *
     167     *  @return number of valid routerinfos imported
     168     *  @throws IOException on most errors
     169     *  @since 0.9.19
     170     */
     171    int requestReseed(InputStream in) throws IOException {
     172        byte[] su3Magic = DataHelper.getASCII(SU3File.MAGIC);
     173        byte[] zipMagic = new byte[] { 0x1F, (byte) 0x8B, 0x08 };
     174        int len = Math.max(su3Magic.length, zipMagic.length);
     175        byte[] magic = new byte[len];
     176        File tmp =  null;
     177        OutputStream out = null;
     178        try {
     179            DataHelper.read(in, magic);
     180            boolean isSU3;
     181            if (DataHelper.eq(magic, 0, su3Magic, 0, su3Magic.length))
     182                isSU3 = true;
     183            else if (DataHelper.eq(magic, 0, zipMagic, 0, zipMagic.length))
     184                isSU3 = false;
     185            else
     186                throw new IOException("Not a zip or su3 file");
     187            tmp =  new File(_context.getTempDir(), "manualreseeds-" + _context.random().nextInt() + (isSU3 ? ".su3" : ".zip"));
     188            out = new BufferedOutputStream(new SecureFileOutputStream(tmp));
     189            out.write(magic);
     190            byte buf[] = new byte[16*1024];
     191            int read = 0;
     192            while ( (read = in.read(buf)) != -1)
     193                out.write(buf, 0, read);
     194            out.close();
     195            int[] stats;
     196            ReseedRunner reseedRunner = new ReseedRunner();
     197            // inline
     198            if (isSU3)
     199                stats = reseedRunner.extractSU3(tmp);
     200            else
     201                stats = reseedRunner.extractZip(tmp);
     202            int fetched = stats[0];
     203            int errors = stats[1];
     204            if (fetched <= 0)
     205                throw new IOException("No seeds extracted");
     206            _checker.setStatus(
     207                _("Reseeding: got router info from file ({0} successful, {1} errors).", fetched, errors));
     208            System.err.println("Reseed got " + fetched + " router infos from file with " + errors + " errors");
     209            _context.router().eventLog().addEvent(EventLog.RESEED, fetched + " from file");
     210            return fetched;
     211        } finally {
     212            try { in.close(); } catch (IOException ioe) {}
     213            if (out != null)  try { out.close(); } catch (IOException ioe) {}
     214            if (tmp != null)
     215                tmp.delete();
     216        }
    138217    }
    139218
     
    148227        private final List<Long> _bandwidths;
    149228        private static final int MAX_DATE_SETS = 2;
    150 
     229        private final URL _url;
     230
     231        /**
     232         *  Start a reseed from the default URL list
     233         */
    151234        public ReseedRunner() {
     235            _url = null;
     236            _bandwidths = new ArrayList<Long>(4);
     237        }
     238
     239        /**
     240         *  Start a reseed from this URL only, or null for trying one or more from the default list.
     241         *
     242         *  @param url if non-null, must be a zip or su3 URL, NOT a directory
     243         *  @throws IllegalArgumentException if it doesn't end with zip or su3
     244         *  @since 0.9.19
     245         */
     246        public ReseedRunner(URL url) throws IllegalArgumentException {
     247            String lc = url.getPath().toLowerCase(Locale.US);
     248            if (!(lc.endsWith(".zip") || lc.endsWith(".su3")))
     249                throw new IllegalArgumentException("Reseed URL must end with .zip or .su3");
     250            _url = url;
    152251            _bandwidths = new ArrayList<Long>(4);
    153252        }
     
    174273            }
    175274            System.out.println("Reseed start");
    176             int total = reseed(false);
     275            int total;
     276            if (_url != null) {
     277                String lc = _url.getPath().toLowerCase(Locale.US);
     278                if (lc.endsWith(".su3"))
     279                    total = reseedSU3(_url, false);
     280                else if (lc.endsWith(".zip"))
     281                    total = reseedZip(_url, false);
     282                else
     283                    throw new IllegalArgumentException("Must end with .zip or .su3");
     284            } else {
     285                total = reseed(false);
     286            }
    177287            if (total >= 50) {
    178288                System.out.println("Reseed complete, " + total + " received");
     
    320430                URLList.addAll(URLList2);
    321431            }
     432            return reseed(URLList, echoStatus);
     433        }
     434
     435        /**
     436        * Reseed has been requested, so lets go ahead and do it.  Fetch all of
     437        * the routerInfo-*.dat files from the specified URLs
     438        * save them into this router's netDb dir.
     439        *
     440        * @param echoStatus apparently always false
     441        * @return count of routerinfos successfully fetched
     442        */
     443        private int reseed(List<URL> URLList, boolean echoStatus) {
    322444            int total = 0;
    323445            for (int i = 0; i < URLList.size() && _isRunning; i++) {
     
    471593         *  @since 0.9.14
    472594         **/
    473         private int reseedSU3(URL seedURL, boolean echoStatus) {
     595        public int reseedSU3(URL seedURL, boolean echoStatus) {
     596            return reseedSU3OrZip(seedURL, true, echoStatus);
     597        }
     598
     599        /**
     600         *  Fetch a zip file containing routerInfo files
     601         *
     602         *  We update the status here.
     603         *
     604         *  @param seedURL the URL of the zip file
     605         *  @param echoStatus apparently always false
     606         *  @return count of routerinfos successfully fetched
     607         *  @since 0.9.19
     608         **/
     609        public int reseedZip(URL seedURL, boolean echoStatus) {
     610            return reseedSU3OrZip(seedURL, false, echoStatus);
     611        }
     612
     613        /**
     614         *  Fetch an su3 or zip file containing routerInfo files
     615         *
     616         *  We update the status here.
     617         *
     618         *  @param seedURL the URL of the SU3 or zip file
     619         *  @param echoStatus apparently always false
     620         *  @return count of routerinfos successfully fetched
     621         *  @since 0.9.19
     622         **/
     623        private int reseedSU3OrZip(URL seedURL, boolean isSU3, boolean echoStatus) {
    474624            int fetched = 0;
    475625            int errors = 0;
    476626            File contentRaw = null;
    477             File zip = null;
    478             File tmpDir = null;
    479627            try {
    480628                _checker.setStatus(_("Reseeding: fetching seed URL."));
     
    498646                        _log.debug("Rcvd " + sz + " bytes in " + totalTime + " ms from " + seedURL);
    499647                }
     648                int[] stats;
     649                if (isSU3)
     650                    stats = extractSU3(contentRaw);
     651                else
     652                    stats = extractZip(contentRaw);
     653                fetched = stats[0];
     654                errors = stats[1];
     655            } catch (Throwable t) {
     656                System.err.println("Error reseeding: " + t);
     657                _log.error("Error reseeding", t);
     658                errors++;
     659            } finally {
     660                if (contentRaw != null)
     661                    contentRaw.delete();
     662            }
     663            _checker.setStatus(
     664                _("Reseeding: fetching router info from seed URL ({0} successful, {1} errors).", fetched, errors));
     665            System.err.println("Reseed got " + fetched + " router infos from " + seedURL + " with " + errors + " errors");
     666            return fetched;
     667        }
     668
     669
     670        /**
     671         *  @return 2 ints: number successful and number of errors
     672         *  @since 0.9.19 pulled from reseedSU3
     673         */
     674        public int[] extractSU3(File contentRaw) throws IOException {
     675            int fetched = 0;
     676            int errors = 0;
     677            File zip = null;
     678            try {
    500679                SU3File su3 = new SU3File(_context, contentRaw);
    501680                zip = new File(_context.getTempDir(), "reseed-" + _context.random().nextInt() + ".zip");
     
    515694                    }
    516695                } catch (NumberFormatException nfe) {}
     696
     697                int[] stats = extractZip(zip);
     698                fetched = stats[0];
     699                errors = stats[1];
     700            } catch (Throwable t) {
     701                System.err.println("Error reseeding: " + t);
     702                _log.error("Error reseeding", t);
     703                errors++;
     704            } finally {
     705                contentRaw.delete();
     706                if (zip != null)
     707                    zip.delete();
     708            }
     709
     710            int[] rv = new int[2];
     711            rv[0] = fetched;
     712            rv[1] = errors;
     713            return rv;
     714        }
     715
     716        /**
     717         *  @return 2 ints: number successful and number of errors
     718         *  @since 0.9.19 pulled from reseedSU3
     719         */
     720        public int[] extractZip(File zip) throws IOException {
     721            int fetched = 0;
     722            int errors = 0;
     723            File tmpDir = null;
     724            try {
    517725                tmpDir = new File(_context.getTempDir(), "reseeds-" + _context.random().nextInt());
    518726                if (!FileUtil.extractZip(zip, tmpDir))
     
    560768                        break;
    561769                }
    562             } catch (Throwable t) {
    563                 System.err.println("Error reseeding: " + t);
    564                 _log.error("Error reseeding", t);
    565                 errors++;
    566770            } finally {
    567                 if (contentRaw != null)
    568                     contentRaw.delete();
    569                 if (zip != null)
    570                     zip.delete();
    571771                if (tmpDir != null)
    572772                    FileUtil.rmdir(tmpDir, false);
    573773            }
    574             _checker.setStatus(
    575                 _("Reseeding: fetching router info from seed URL ({0} successful, {1} errors).", fetched, errors));
    576             System.err.println("Reseed got " + fetched + " router infos from " + seedURL + " with " + errors + " errors");
     774
    577775            if (fetched > 0)
    578776                _context.netDb().rescan();
    579             return fetched;
     777            int[] rv = new int[2];
     778            rv[0] = fetched;
     779            rv[1] = errors;
     780            return rv;
    580781        }
    581782
Note: See TracChangeset for help on using the changeset viewer.