Compare commits

..

745 Commits

Author SHA1 Message Date
zzz
ff5abfb4b7 0.9.6 2013-05-27 18:17:53 +00:00
zzz
370d9dfea1 -24 2013-05-25 12:12:46 +00:00
kytv
2a00272efe debian: read /etc/default/i2p in /usr/bin/i2prouter
This will allow overrides to be set without editing /usr/bin/i2prouter.

i2prouter may be replaced during upgrades. /etc/default/i2p will only be
changed by debconf (e.g. "dpkg-reconfigure i2p").
2013-05-24 21:30:46 +00:00
kytv
1bd4937a4b geoip.txt update
Based on Maxmind GeoLite Country database from 2013-05-08
2013-05-24 09:13:46 +00:00
kytv
0ac2abd5eb debian: bump changelog version to 0.9.6 2013-05-24 09:10:00 +00:00
meeh
efe5098f24 Disabling HH's server for this version because it's down and I haven't got in contact with him. 2013-05-23 20:03:09 +00:00
meeh
c73163f525 merge of '56506455244b72ac03b5a5cb832496e367f454b2'
and '6aeeb6555b2fb4e69f167487ca20b143939c809c'
2013-05-22 19:51:04 +00:00
meeh
bf317f61c5 Updating the certificate for reseed.info 2013-05-22 19:50:02 +00:00
zab2
b1b13c41f0 merge of '9f901bf6cca59e5a24595ef80a2fbb586e259281'
and 'e31714127884dc817acde4cf97cb9c7d8cebc92b'
2013-05-21 19:04:55 +00:00
zab2
47c3a56aca Ticket 928 - prevent a CKE during write 2013-05-21 19:03:58 +00:00
zzz
2f39574123 log tweaks 2013-05-21 13:39:43 +00:00
kytv
8b1ab4b8d2 create ./build when "ant jbigi" is run by itself 2013-05-20 20:31:18 +00:00
kytv
2e0a1b9a0e German translation updates from tx, updated en po files for pushing to tx 2013-05-15 22:04:43 +00:00
zzz
4fae18a719 * UPnP: Detect devices without port forwarding capability (ticket #930) 2013-05-15 14:21:15 +00:00
zzz
d9beaa7591 * NetDB: Increase floodfill count for good 2013-05-15 14:19:01 +00:00
zzz
2ba5ad558b * i2psnark:
- Adjust target piece size calculation
   - Tweak to make it easier for new peers to connect
2013-05-15 14:18:24 +00:00
kytv
de6bb12b95 debian: refresh patches 2013-05-15 13:39:24 +00:00
kytv
aa2715cced i2prouter: abort immediately if I2P_CONFIG_DIR cannot be created 2013-05-15 13:38:34 +00:00
kytv
b096834a54 installer/resources/i2prouter: various bugfixes
- Explicitly specify shell when RUN_AS_USER is set. This allows I2P to start
  under limited accounts that do not have a defined shell.
- When installing as a service, point out that I2P_CONFIG_DIR may need to be
  set. I2P_CONFIG_DIR defaults to $HOME/.i2p for the user that installed I2P
  and when running as a service this may not be desired.
  (e.g., RUN_AS_USER=i2p & I2P_CONFIG_DIR=/root/.i2p)

(The RUN_AS_USER shell problem was spotted at https://github.com/mattias-ohlsson/i2p/blob/master/i2p.spec)
2013-05-15 13:04:46 +00:00
kytv
c1da7f778b improvements to jbigi scripts
support for Solaris (tested with Solaris 11 x86)

mbuild-all.sh:
- output correctly formatted file names (tested in Solaris x86, FreeBSD (x86 and x64) and Linux (x86 & x64))
- switch from echo -e to the more portable printf
- more error checking, comments

debian/patches: refreshed based on changes to core/c/*
libjcpuid-x86_64-solaris.so: built in solaris 11 x86 with
                             java 1.7.0_07 and gcc 4.5.2, stripped
2013-05-12 00:08:52 +00:00
zzz
dca5e9889a finals 2013-05-07 13:49:31 +00:00
zzz
67beebf859 * HandleDatabaseLookupMessageJob: Improve efficiency by only looking up
Hash in the netDb once, then casting to correct type.
   Log cleanups.
2013-05-07 13:37:18 +00:00
zzz
16c8a19be8 * Streaming: Throw chained IOE from streams to get correct location 2013-05-07 13:09:03 +00:00
zzz
0c03b6ba82 i2psnark: More details page fixups;
List directories first
2013-05-06 15:11:02 +00:00
zzz
cd6376e368 remove DOS line endings in jsps 2013-05-06 13:14:44 +00:00
zzz
c26eba9693 * Console: Fix Jetty thread pool policy and thread name 2013-05-06 12:29:18 +00:00
zzz
b7fca3af42 * Transports: Clean up internal/external port confusion (ticket #873)
- Bind SSU to configured internal, not external, port at startup
   - Use only internal ports for UPnP (getRequestedPort() fixups)
   - Don't have NTCP follow frequent SSU port changes
   - Don't use external SSU port for internal NTCP port
   - Display internal SSU port on /confignet
2013-05-06 11:24:02 +00:00
kytv
7527a02c60 build.xml: refactor "noExe check" to remove duplication 2013-05-04 19:00:39 +00:00
zab2
5e734088e3 reduce severity of CancelledKeyExceptions
trac ticket 928
2013-05-03 13:47:10 +00:00
kytv
6265bdf026 merge of '00acf6715c7e3d5519672b335bb833f2f88f5ca1'
and '4790dff566ce61cb8a5bfefa0c423df44a784fa5'
2013-05-02 10:19:17 +00:00
str4d
0d78ddf872 HTML fixes in readme_ar.html 2013-05-01 22:23:42 +00:00
zzz
10efecaa9c * IRC Server tunnel: Reject bad protocols immediately 2013-05-01 20:52:50 +00:00
kytv
689b045a9b html validation fixes
xmllint didn't find these problems (but tidy did).
2013-05-01 19:52:21 +00:00
kytv
7692905ba5 fix viewmtn url
(*sigh*)
2013-05-01 18:07:20 +00:00
kytv
0ef3bb1deb debian: s/UNRELEASED/unstable/ due to updated packages being built 2013-05-01 17:51:17 +00:00
kytv
4c279a192a Switch viewmtn links from zzz's to mine 2013-05-01 17:48:14 +00:00
zzz
af7eaf1f05 * BuildRequestor: Slow down build loop if we have no exploratory tunnels
(ticket #926)
2013-05-01 17:26:07 +00:00
zzz
c198e216fd susidns css tweak 2013-05-01 17:24:09 +00:00
zzz
2325bffbcb enhance main() for debugging 2013-05-01 17:23:50 +00:00
kytv
3d3e05d43d debian: don't ship jasper-compiler.jar anymore
I didn't realize that non-existent jars specified in a classpath is not an
error.
2013-05-01 13:37:15 +00:00
kytv
c62ae69fe5 debian: bump standards version, don't package 'dummy jars'
note: jasper-compiler is kept due to it being referenced at http://www.i2p2.i2p/plugin_spec
2013-04-30 23:26:42 +00:00
str4d
686aa870ea Updates to readme_ar and a CSS tweak from hamada (ticket #489) 2013-04-30 12:35:45 +00:00
zzz
ecac69134d param fix 2013-04-30 01:21:23 +00:00
zzz
8a99be1db3 move page nav 2013-04-29 22:40:49 +00:00
zzz
26f0c98ef8 * Transports:
- Initial prep for multiple addresses per style
   - Simplify NTCP send pool
2013-04-29 18:09:21 +00:00
kytv
650b920e11 I2PTunnel: break out of frame when using the "test server bypassing i2p" link 2013-04-29 17:09:25 +00:00
kytv
7a43bd87c2 remove unused param (javadoc fix) 2013-04-29 17:07:08 +00:00
zzz
3a4ac1fc4e one more param fix; javadoc fix 2013-04-29 11:50:23 +00:00
zzz
188ff3392d * i2psnark: Support HTTP request ranges so in-browser and other http-aware media players work better.
Single range only; no multipart
2013-04-28 16:46:52 +00:00
zzz
0cf7e91475 baseline class from Jetty 7.6.10 2013-04-28 16:44:30 +00:00
zzz
609bbac8d5 * i2psnark:
- Only show lower section on first page
   - Hide peer count if not connected
   - Dir page CSS tweaks
2013-04-28 16:43:40 +00:00
zzz
f4431b8d1e more parameter fixes 2013-04-27 22:34:59 +00:00
zzz
45bf2e0715 more classes pkg private 2013-04-27 22:34:39 +00:00
zzz
d7040a23e4 page count fix and cleanups 2013-04-27 16:08:35 +00:00
zzz
6f8fe0ecac add epub mime type 2013-04-27 14:51:07 +00:00
zzz
7181e3eb87 * i2psnark: Ensure current stats and correct event delivered in announce 2013-04-27 14:34:00 +00:00
zzz
011e91140c * i2psnark: Improve page nav 2013-04-27 13:14:43 +00:00
zzz
0f1224de98 * installer: Fix DOS line endings on misc. files (ticket #872)
* SusiDNS:
   - Trim and sort config form data
   - Fix DOS line endings on config files in Linux (ticket #872)
2013-04-26 20:32:58 +00:00
zzz
2e356172d4 document ignored RouterAddress expiration (ticket #832) 2013-04-26 17:12:37 +00:00
zzz
c6bf9a7cf6 deprecate isJobActive() ticket 670 2013-04-26 16:45:52 +00:00
zzz
0816cfe273 * Plugins: Track pending plugin clients better, don't hold references,
start delayed clients from SimpleTimer2 instead of Job queue (ticket #670)
2013-04-26 16:41:09 +00:00
zzz
1cea18346b * Console: Show log location on /logs even if not opened yet (ticket #905) 2013-04-26 13:36:38 +00:00
zzz
0d4bc500ee * HTTP proxy: Verify nonce count in digest auth 2013-04-26 13:02:56 +00:00
zzz
ff313e0301 * i2psnark: Use smaller piece size for small torrents 2013-04-26 13:01:16 +00:00
kytv
85001d2622 process debian/po/es.po with update-po 2013-04-25 15:10:40 +00:00
kytv
654b240e9d translation updates
* Portuguese, Russian, Spanish, and Swedish translation updates from Transifex
* ant poupdate run for EN for submission to tx
2013-04-25 15:06:27 +00:00
str4d
85f3f5615f Allow the "AUTHENTICATE" command in IRC tunnels (ticket #904) 2013-04-25 05:27:55 +00:00
zzz
813a1981d9 * Console, TunnelControllerGroup: Don't register shutdown hook if ClientAppManager is present
* JettyStart: Fixes for use by plugins
 * RouterAppManager: Add shutdown hook
2013-04-24 15:45:15 +00:00
str4d
57fd46d3a1 Updated i2p.c default classpath with new Jetty jars, fixed separator 2013-04-24 03:53:12 +00:00
str4d
ffbbfdfc0d merge of 'a58d3f77fd66a83579a9978f954077bc0cd3dfed'
and 'c61f304e5ee2d59c51c4e700ab47e61d479257d2'
2013-04-24 03:48:35 +00:00
str4d
31bc67a1cd Added launch.properties for i2pExe based on i2pstandalone.xml and doBuildEXE target 2013-04-24 00:30:39 +00:00
kytv
ec4f2d2100 merge of '3cff53ae6e9e995199ab4c7c4ce5fa78ec417768'
and 'e824a448e5e49d646a33e7be13f648f66b1b6a47'
2013-04-24 00:01:01 +00:00
str4d
5b40914552 Removed some unnecessary code from i2pExe 2013-04-23 21:19:28 +00:00
zab2
e8025f09bd merge of '3c164e606c1ed364a6caf2b5b77abbdf819a2bc7'
and 'ebe0842bec96b1e0ed3b8e0c18d4ea05ba7cb981'
2013-04-23 19:27:52 +00:00
zzz
aa547a1610 * i2ptunnel: Block b32.i2p supercookies 2013-04-23 18:23:38 +00:00
zzz
22025b0c3a * Console: Fix Jetty digest auth bug causing repeated password requests
I2P fixes for out-of-order nonce counts.
   Based on DigestAuthenticator in Jetty 7.6.10.
   Includes the nonce count verification code from Tomcat 7.0.35.
   ref: http://jira.codehaus.org/browse/JETTY-1468 which was closed not-a-bug.
   ref: https://bugs.eclipse.org/bugs/show_bug.cgi?id=336443 in which the
   Jetty implementation was introduced.
2013-04-23 18:22:48 +00:00
zzz
4358d11191 Baseline checkin of DigestAuthenticator from Jetty 7.6.10 before mods 2013-04-23 18:19:49 +00:00
zab2
5fd63c12a8 remove an ifdef that is not relevant to I2P 2013-04-23 18:05:43 +00:00
str4d
37ff4090b4 merge of '97f6b32a68c76e9cbe8832d250144facb6aa729e'
and 'd9b5e2fc62256d9dc0d320fe593d56f0252b7f48'
2013-04-22 20:38:52 +00:00
str4d
9550de6760 disapproval of revision '4747eea80e136e04c9a239f0b6ecd9ef134c4d5a' 2013-04-22 20:37:42 +00:00
kytv
f5838ffefb add new jetty7 jars to the i2p.exe classpath 2013-04-21 20:26:41 +00:00
zzz
2a374c9b22 bump to -12 after prop 2013-04-21 16:07:08 +00:00
zzz
59ba47eca5 propagate from branch 'i2p.i2p.zzz.winfix095' (head 7d31b90b87adb2c0cfb837e5b66cc4c223766331)
to branch 'i2p.i2p' (head b004014ccfbca6241a090d5b47f1228702f4dfcc)
2013-04-21 15:57:22 +00:00
zzz
60d0b2976b * AppManager:Add HTML debug output 2013-04-21 15:41:34 +00:00
zzz
a44e75201f * Streaming: Pcap window size fixes 2013-04-21 15:40:08 +00:00
zzz
eb3de929bf Pluck of 48ac112fe938c8e960413ad60f64d313a1e5c9ac and e415e24aca895c5a1f88380b1a3946e3b49749a9
* Add new *.i2p2.de certificate
* Added backup's ressed server. (Thanks backup!)
* Temporary removing h2ik's server since he's been AWOL since 06-03-2013 and he's reseed server is down.


applied changes from 185bc62d33224812060d2f68266a029935fb710d
             through 48ac112fe938c8e960413ad60f64d313a1e5c9ac

applied changes from 1194eb12084302380b4315b20e5ae0c574ce1be3
             through e415e24aca895c5a1f88380b1a3946e3b49749a9
2013-04-21 13:47:16 +00:00
str4d
d0fa9f8f1e And back to HTTP 403 for Bad URI (we are refusing to fulfill the request) 2013-04-21 13:36:59 +00:00
str4d
a3886b0080 Use HTTP 404 for Bad URI (c/f jetty, lighttpd) 2013-04-21 13:30:22 +00:00
str4d
b872764624 Use HTTP 400 for Bad URI 2013-04-21 13:27:28 +00:00
str4d
075b1fd6f6 Ticket #891 - return "Invalid Request URI" for URIs with illegal characters 2013-04-21 03:20:43 +00:00
zzz
2430e180f3 Add EXTRA version "win1" in prep for Windows-only point release.
We don't want to bump BUILD as it could cause confusion,
and would cause all installs to attempt update via torrent.
2013-04-20 19:07:11 +00:00
zzz
0c22af9578 Convert install.xml to use new utility.jar Main.main()
(ticket #912)
2013-04-20 19:03:38 +00:00
zzz
4976e52389 Pluck of 40d650b134e48bdb0bb636227381c22217365c47
* WorkingDir: Correctly strip DOS line endings while migrating,
              to fix eepsite location on 0.9.5 Windows installs (ticket #919)

applied changes from cc74155815c98674b74cd7d9abb59704005d6b85
             through 40d650b134e48bdb0bb636227381c22217365c47
2013-04-20 18:53:01 +00:00
zzz
88afb23a8c Backport of b6b65cd637f41758bfd38692772ffade3c8cbbbc
Installer: run fixperms.bat all Windows versions except XP/2003.
Wasn't being run on Windows 8.
2013-04-20 18:46:27 +00:00
zzz
a7a0ca87c9 Branch from 0.9.5 release.
Implement new Main wrapper class for utility.jar, to
work around izpack ticket #162 http://jira.codehaus.org/browse/IZPACK-162
which prevents us from specifying a main class as it fails on
Windows installations when a full path including a drive letter is specified
(ticket #912)
2013-04-20 18:42:55 +00:00
kytv
7371718afc Installer: run fixperms.bat all Windows versions except XP/2003. 2013-04-19 13:41:56 +00:00
zzz
1e5ffe636f * Updates:
- Notify manager about all available update methods at once, so the priority
     system works and it doesn't only update via HTTP
   - Start router update download at startup if available
   - Only check plugins when core version increases, not decreases, so we
     don't update plugins when downgrading
   - Limit length of URL shown on summary bar
2013-04-19 11:49:22 +00:00
zzz
ca1e8d09cc debug log 2013-04-19 11:47:05 +00:00
zzz
ddc5e2c23f * WorkingDir: Correctly strip DOS line endings while migrating,
to fix eepsite location on 0.9.5 Windows installs (ticket #919)
2013-04-19 11:44:57 +00:00
zzz
3086fd3ce0 * LogManager: Add support for saving properties added in recent releases 2013-04-19 11:42:32 +00:00
zzz
5ea2832ae0 * AppManager: Register jetty, console, and SAM with manager 2013-04-19 11:41:35 +00:00
zzz
5cb449efed * i2psnark: Disable spellcheck in more form fields 2013-04-19 11:40:36 +00:00
kytv
46f8344d30 Add new *.i2p2.de certificate 2013-04-18 15:51:17 +00:00
zzz
b370fe6838 * SusiMail: Fix loading of Jetty classes 2013-04-18 15:25:33 +00:00
zzz
d6b28a4eb1 * i2ptunnel: Set target=_top in all external links to break out of console iframe 2013-04-18 15:24:46 +00:00
zzz
72ead2bbcc * i2psnark: Fix params after P-R-G 2013-04-18 15:24:01 +00:00
zzz
648701afdd * Eepsite: Fix jetty.xml configuration of ThreadPool 2013-04-17 21:06:52 +00:00
zzz
389f540f44 less dots 2013-04-17 21:04:21 +00:00
echelon
ceda25fb36 added browser http proxy setup to initial news 2013-04-17 18:21:55 +00:00
zzz
c4e2019657 * SusiDNS: Set target=_top in all external links to break out of console iframe 2013-04-17 17:06:34 +00:00
zzz
b64b2629b9 * i2ptunnel: Fix default form action (ticket #882) 2013-04-17 17:04:34 +00:00
zzz
9443a96f0c * Systray: Better detection of 64-bit Windows (tickets #756, #912)
- Don't even instantiate systray unless on 32-bit Windows
2013-04-17 14:49:25 +00:00
zzz
6af73d087b * Console: Better handling of missing font for graphing (ticket #915)
- Remove unused imports
2013-04-17 14:45:24 +00:00
zzz
c61f2af8b3 * SAM: Implement ClientApp interface (ticket #347) 2013-04-16 21:07:00 +00:00
zzz
a3aee79e9c * ClientAppManager: Add method to look up clients by class and args
* Console: Implement stopping of clients using the ClientApp interface
            (ticket #347)
2013-04-16 14:59:18 +00:00
kytv
7d0f626fd5 remove mime types already set by jetty 2013-04-15 21:41:53 +00:00
zzz
e34a98620c merge of '186e5e48c613c85b8e11c61ec920a40837bfae8e'
and '3449c389b42e40b9c9a07848a868bb745c5c4540'
2013-04-15 20:59:28 +00:00
zzz
6c32a05378 2nd instance bootstraps DHT from 1st instance 2013-04-15 20:56:10 +00:00
kytv
ec4c830c09 i2psnark: update mime types 2013-04-15 20:28:22 +00:00
zzz
9e5d809650 trim form values 2013-04-15 20:23:39 +00:00
zzz
1746a81234 update servlet base after changing dir 2013-04-15 18:54:47 +00:00
zzz
efe7a7536d * i2psnark:
- Add data directory configuration to GUI (ticket #768)
   - Add page size configuration to GUI
2013-04-15 18:39:59 +00:00
zzz
11dd7f6b8c * Console: Move from deprecated Jetty SSL methods to SslContextFactory 2013-04-15 15:53:29 +00:00
zzz
e29bb5b88b * i2psnark:
- Mime type fixes
   - Remove web classes from jar
2013-04-15 12:12:35 +00:00
zzz
57b794f72a * Jetty logging: Fix logging using I2PLogger class;
log ignored messages at debug level
2013-04-14 14:02:43 +00:00
zzz
8bfe3f632e * i2psnark:
- Set unique tunnel nickname for additional instances
   - Increase page size to 50
   - Restore 1-arg SnarkManager constructor for compatibility
   - Add note about DHT file w/ multiple instances, to be fixed
   - Log tweak
2013-04-14 14:00:47 +00:00
zzz
21e47e61f0 * Console: Add /graph support for bw.combined, consolidate
rendering code (ticket #890)
2013-04-13 12:13:55 +00:00
zzz
49cc6b5100 * i2psnark:
- Limit number of torrents displayed; add previous/next page buttons
   - Only register one instance with UpdateManager
   - New icons from famfam/silk, same license
2013-04-13 12:12:22 +00:00
kytv
10a42c8b0d debian: add new jetty7 jars to package 2013-04-13 00:23:24 +00:00
zzz
f59ea790ca Javadoc fixups for Jetty 7 2013-04-12 13:53:54 +00:00
zzz
28f1170d95 history for prop, -1 2013-04-10 17:39:27 +00:00
zzz
8eb7cf7bae propagate from branch 'i2p.i2p.zzz.jetty7' (head 12e512b792594fe6a291ad3ab303fca30228391b)
to branch 'i2p.i2p' (head f3775dd82af85ba335258bd9f0fc06131a1daaa9)
2013-04-10 17:24:11 +00:00
zzz
1be0695a21 remove extra semicolon 2013-04-10 17:23:43 +00:00
zzz
65480456cd - I2NP: Ignore unused 7 bits of the Database Lookup Message,
so we can use them later
2013-04-10 17:22:51 +00:00
zzz
5962577b53 - I2NP: Ignore unused 7 bits of the Database Lookup Message,
so we can use them later
2013-04-10 17:06:32 +00:00
zzz
1222776da3 tweak proxy error page 2013-04-10 17:04:07 +00:00
zzz
13633a0532 remove debug id 2013-04-10 17:03:15 +00:00
zzz
1eda9e9053 set ethertype to IPv4 2013-04-10 17:01:54 +00:00
zzz
2557a0bd84 increase threads 2013-04-10 17:00:54 +00:00
str4d
e1c533e9de Fixed path to start.ico 2013-04-08 22:44:58 +00:00
zzz
bb8183d0ee - Backup up more Jetty 6 config files before migration
- Try to avoid zip file closed exceptions
  - Fix jetty.xml, switch from deprecated WebAppDeployer to WebAppProvider
2013-04-08 15:29:02 +00:00
zzz
9478a84af7 - Switch from Jetty 7.6.8 to 7.6.10; check in jars
- Re-enable web downloads for easy jetty updating
  - Add dependency checking in apps/jetty build
  - Other build.xml tweaks
2013-04-07 15:01:02 +00:00
zzz
56eba28a50 propagate from branch 'i2p.i2p' (head d30ab8d5835ca55d63913342f0d28169c88e5d77)
to branch 'i2p.i2p.zzz.jetty7' (head fdd1d82c4bb26ed934170c34dd803c342a183a91)
2013-04-07 13:33:13 +00:00
zzz
f8d323bc7b propagate from branch 'i2p.i2p' (head 5737078c5993e2fcf73520cc610a71125b12520b)
to branch 'i2p.i2p.zzz.jetty7' (head a93a47d79b1db119ec8c62b46a4a4e226043bd17)
2013-04-07 13:20:34 +00:00
str4d
8857fe5550 Set defaults based on installer/i2pstandalone.xml and build.xml/doBuildEXE 2013-04-04 22:25:05 +00:00
str4d
45a38a5425 Only use original argc/v if there are arguments, otherwise use launch.properties or defaults 2013-04-04 22:15:21 +00:00
str4d
7f471910ed Marked Windows-specific code in preparation for a cross-platform binary 2013-04-04 21:51:57 +00:00
str4d
f6190dd82d Get a simple I2P.exe working 2013-04-03 01:55:02 +00:00
str4d
51f072cc72 Migrated limewireExe to i2pExe 2013-04-03 01:52:14 +00:00
str4d
b65898e0dd Ticket #741 - Added limewireExe source 2013-04-03 01:39:33 +00:00
kytv
7b753c9d30 merge of '48ac112fe938c8e960413ad60f64d313a1e5c9ac'
and 'c4b1087c95c82bb9dde50c078a0c2c0e86c562bc'
2013-04-02 22:46:25 +00:00
dev
dc8d70102c merge of '185bc62d33224812060d2f68266a029935fb710d'
and '381b15133084a1b3e1c37f66a62a768fedefd3d4'
2013-04-02 22:12:57 +00:00
dev
2cbb157f2d add lists.i2p2.i2p 2013-04-02 22:10:08 +00:00
meeh
2c47c21038 * Added backup's ressed server. (Thanks backup!)
* Temporary removing h2ik's server since he's been AWOL since 06-03-2013 and he's reseed server is down.
2013-04-01 13:18:47 +00:00
kytv
5904d5764c Debian: update changelog 2013-03-31 12:51:20 +00:00
kytv
d5443a34ea Debian: explicitly set permissions in postinst on /etc/i2p/wrapper.config (fixes #906) 2013-03-31 12:47:53 +00:00
kytv
af79b74c8c checkcerts.sh: cross platform support on *NIX
- function to convert dates to Julian to perform date calculation if GNU date is
  not present.
2013-03-30 21:52:01 +00:00
kytv
bfc327833c checkcerts.sh: add some support for non-Linux systems
Date computations as performed in this script require the use of GNU date,
which is only available by default on Linux systems. With this check-in we
explicitly check for the existence of GNU date before continuing with the date
calculations.

Previous versions of this script relied on 'certtool' to print the expiration
dates but certtool isn't available by default on non-Linux systems either. The
previous check-in added support for using OpenSSL, retaining the old behavior
on non-Linux systems.

(Also a re-arrangement of the date warning logic)
2013-03-30 14:24:59 +00:00
kytv
427abb081c remove debug text 2013-03-30 02:26:37 +00:00
kytv
6992090cda various updates to checkcerts script
- add support for 'openssl'
- parse expiration date, failing if expired or if expires within 30 days
- warn at 60
2013-03-30 02:22:23 +00:00
zzz
9b0c481525 0.9.5 2013-03-08 13:03:50 +00:00
zzz
77cfe0be01 graphs.jsp: Fix saving settings (ticket #857) 2013-03-03 20:32:02 +00:00
kytv
041da814d2 merge of '4482eec8563d6ed220c2042b18fc09164aaa4404'
and 'ce2de3b5c7bc1fcd077ff9d6327eaf24758d2a13'
2013-03-03 18:42:46 +00:00
kytv
7b7f3ea025 update geoip based on the Maxmind GeoLite Country database from 2013-02-19 2013-03-03 17:22:09 +00:00
kytv
53d5c0854f removing email address per request 2013-03-03 17:15:06 +00:00
meeh
b2f1e78d62 Temporary removing ju1c3d's reseed server until it's up and working fine on the new system. 2013-03-03 17:08:26 +00:00
kytv
9ba17d2e90 French, German, Norwegian, Polish, and Portuguese translation updates from tx 2013-02-22 13:20:41 +00:00
kytv
cc18f62fb5 Add new syndie hostnames 2013-02-13 20:50:05 +00:00
kytv
8950cc48a6 Flag of Curaçao, courtesy of David Benbennick, released into the public domain 2013-02-13 20:47:29 +00:00
zzz
51edaed610 NetDB: Randomize delay before floodfill store verify 2013-02-12 14:58:52 +00:00
zzz
3a2accdebb * Update: Bump torrent update to 3% of routers 2013-02-10 16:38:09 +00:00
zzz
6cef4f90e1 * Logs: Again, fix setting log filename (ticket #805) 2013-02-10 16:37:06 +00:00
zzz
f5e416d6bf Wrapper 3.5.17 compiled on Raspberry Pi (ticket #826)
GPLv2
binaries stripped

gcc (Debian 4.6.3-12+rpi1) 4.6.3

java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.5) (6b24-1.11.5-1+rpi1)
OpenJDK Zero VM (build 20.0-b12, mixed mode)

Processor	: ARMv6-compatible processor rev 7 (v6l)
BogoMIPS	: 697.95
Features	: swp half thumb fastmult vfp edsp java tls 
CPU implementer	: 0x41
CPU architecture: 7
CPU variant	: 0x0
CPU part	: 0xb76
CPU revision	: 7

Hardware	: BCM2708
Revision	: 0002
2013-02-10 15:02:04 +00:00
zzz
5eba38a24e * NetDB:
- Encrypt DatabaseLookup messages out exploratory tunnels
     when we already have the RI of the ff
   - Don't use multiple routers from the same /16 in lookups or stores
2013-02-09 19:29:08 +00:00
zzz
7f5d6ca1c7 javadocs 2013-02-09 19:28:12 +00:00
kytv
e4318e95a5 German, Polish, Portuguese, Spanish, and Swedish translation updates from Transifex 2013-02-06 02:39:44 +00:00
str4d
eaa86664bd Fixed SOCKS mapping terminology, bumped history 2013-02-04 11:29:30 +00:00
str4d
5a1053e4fb Allow any domain name to be mapped to an IP
This enables .onion domain names to be accessed by clients that are being
routed through the SOCKS tunnel by e.g. proxychains (assuming that the SOCKS
tunnel has been configured with a SOCKS outproxy that exits into Tor). If the
.onion is not mapped to an IP address, the client would attempt a DNS lookup
which would of course fail to find the .onion.

Clearnet domain names can also be mapped to IPs, but this is irrelevant as DNS
lookups work through SOCKS (via the configured outproxy).
2013-02-04 11:21:26 +00:00
str4d
0052ebf334 Set SOCKS5 addressType to AddressType.DOMAINNAME on a successful mapping 2013-02-04 11:13:23 +00:00
kytv
d9f7b24cc7 use short name for diftracker 2013-01-31 18:18:48 +00:00
kytv
67ca0a4d20 Norwegian translations:
- enable Bokmål in router
- add to tx config
- add Bokmål translations from transifex
2013-01-31 17:51:01 +00:00
kytv
fea91a35f6 fix Norwegian translation, add to tx config 2013-01-31 16:42:57 +00:00
meeh
3214bc4f81 merge of '4e5a2d2f78b9a7603ece4e4b54720e83e062cbf4'
and '8bbaf8414a2475919844450aad53b325ee0f7e84'
2013-01-31 15:40:15 +00:00
zzz
a0befe59c3 * EepGet:
- Fix URL when not proxied to conform to RFC 2616
   - Add port to Host header to conform to RFC 2616
2013-01-31 12:54:23 +00:00
meeh
5f614db59b Adding a new reseed host. http(s)://netdb2.i2p2.no
Using certificate from cacert.org

Thanks to ju1c3d, ju1c3d@mail.i2p
2013-01-30 15:34:28 +00:00
meeh
cc4b03604d Adding Norwegian Bokmål translation to i2ptunnel. 2013-01-29 18:14:34 +00:00
zzz
573692dbdf * Console: Catch IllegalStateException storing nonces (ticket #852) 2013-01-29 13:48:00 +00:00
zzz
78dcfd830c * Translations:
- Use JVM language name if available
  - Correct Estonian language code from ee to et
2013-01-29 13:44:36 +00:00
zzz
95d0dc0419 fix BuildHandler NPE from previous checkin 2013-01-28 12:50:04 +00:00
zzz
9247dc898c * BuildHandler:
- Add early throttler based on previous hop
   - Limit concurrent next-hop lookups
2013-01-27 16:24:29 +00:00
zzz
bd900d8d55 increase ff count 2013-01-27 16:21:09 +00:00
zzz
a9eb48c4c6 javadoc 2013-01-27 16:20:26 +00:00
zzz
8afe7c261f * RandomSource: Seed from SecureRandom too 2013-01-27 16:18:56 +00:00
zzz
543870ff02 change injection errors to warns 2013-01-27 16:17:29 +00:00
str4d
92707efe8a history bump 2013-01-24 00:18:11 +00:00
str4d
42040eb6c8 Added IP -> I2P URL mapping support to SOCKS client tunnels
To use, add custom options to the SOCKS client tunnel like:

ipmapping.127.12.12.12=stats.i2p

Then save and restart the tunnel.
2013-01-24 00:14:03 +00:00
zzz
18e369bcf4 - Use servlet path everywhere, so the war can be renamed
- Use servlet path as base for config file and data directory names,
    so we may have multiple instances running together
  - Don't override service(), use doGet() and doPost() instead
2013-01-23 22:44:52 +00:00
zzz
4ba8f02f59 * Eliminate Jetty dependencies in i2psnark for good.
Required due to webapp classloader changes in Jetty 7,
  we can no longer access or extend Jetty classes.
  - Extend javax HttpServlet instead of Jetty's DefaultServlet
  - Implement BasicServlet to replace functions of DefaultServlet
  - Add MimeTypes implementation to add to servlet's defaults
  - Add local mime.properties file, remove checks in I2PSnarkServlet for those
    we were missing
  - Eliminate all use of Jetty utility classes including MimeType, Resource,
    Buffer, Cache, URIUtil, ...

TODO:
  - Use servlet path everywhere, so the war can be renamed
  - Don't override service()
2013-01-23 20:26:50 +00:00
str4d
a7fc8bdf53 Added a link to the summary bar for mobile users on /home 2013-01-21 08:38:00 +00:00
str4d
3710346764 history 2013-01-21 06:23:19 +00:00
str4d
bb0d2ef17c Added User Agent string for Opera Mobile
On tablets the UA is "Opera Tablet" so tablets will use the desktop console.
2013-01-21 06:01:42 +00:00
str4d
d5a870226c Added option to /configui to force the mobile console to be used 2013-01-21 05:59:53 +00:00
str4d
34aa3ac207 Updated history.txt 2013-01-19 03:51:42 +00:00
str4d
7d38041d23 Tweak so Android tablets use the normal routerconsole 2013-01-19 03:46:38 +00:00
str4d
e643d0a086 Fixed up mobile view of routerconsole with a mobile.css in each theme 2013-01-19 03:42:54 +00:00
kytv
dcd655fa4b * Translations
- Hungrarian, Italian, Portuguese, Russian, and Swedish translation updates
    from Transifex
  - Refresh of **/messages_en.po
2013-01-17 13:14:08 +00:00
zzz
f57f49c3c5 propagate from branch 'i2p.i2p' (head f33e0980fd48ba4acda12d2079f2a4834a710ae4)
to branch 'i2p.i2p.zzz.jetty7' (head bd1a64f7262ad5bbea3529675f1f055b9ad257a8)
2013-01-13 12:38:05 +00:00
zzz
4f146772e7 * I2CP: Failsafe check for delivery job requeueing forever (ticket #819) 2013-01-12 18:18:17 +00:00
zzz
083dffe8ed try again to prevent IllegalStateException on Java 5 2013-01-12 18:17:31 +00:00
zzz
c43a73e756 log and javadoc tweaks 2013-01-12 18:16:38 +00:00
zzz
0c94680a45 * NetDB: Split up files into subdirectories 2013-01-12 18:14:51 +00:00
zzz
832c0ff683 * SAM: Force i2cp.messageReliability=None (ticket #819) 2013-01-12 18:13:59 +00:00
zzz
95b4fe7378 * jobs.jsp: Add table of pending jobs 2013-01-12 18:13:19 +00:00
zzz
ed12bcefdb * EepGet:
- Fix format of last-modified header to use strictest RFC 822
  - Stop immediately if socket connection to proxy fails
  - Don't forget lastModified/etag headers after redirect
  - Note SocketTimeout API breakage for Syndie
2013-01-12 18:12:35 +00:00
kytv
41af00a7d6 don't run gettext if 'require.gettext' is set to false 2013-01-10 16:51:06 +00:00
kytv
e34cd0ba3f merge of '27711f734eca9313f7e0742dc1a6df964b744b86'
and '4d27e2149e5bb50280599426f3884dfcc04f920a'
2013-01-10 15:09:20 +00:00
kytv
18664d39f3 add bumpBuild target 2013-01-10 14:43:15 +00:00
zab
680c31b843 Fix/update/refactor InboundTest 2013-01-07 19:03:30 +00:00
zab
ba5005c467 Fix OutboundGatewayTest
Refactor as much as possible into GatewayTestBase
2013-01-07 18:38:13 +00:00
zab
7a8fde6637 Refactor common code between Inbound and Outbound Gateway tests in a base class
OutboundGatewayTest still fails, investigating...
2013-01-06 23:02:10 +00:00
zab
973e0e7448 Fix/update InboundGatewayTest 2013-01-06 21:42:15 +00:00
kytv
101702552f re-enable DataHelperTest since the jenkins test was a success 2013-01-06 02:41:42 +00:00
kytv
8aa7433a80 merge of '2246f1b81c19ddc2c058e68870f1445b9cca1598'
and '956cf5bff87f174141628efbad07e028e30fc4c9'
2013-01-06 02:24:09 +00:00
kytv
e7d48f1d3c - s/classpath/javac.classpath/ I'm fairly sure that this must have been added
in error.
- add jenkins.cobertura.report target. The jenkins plugin couldn't find the
  sources, so I'm hoping this helps it out.
- add debug lines cobertura needs
2013-01-06 02:22:10 +00:00
zab
7e7a68a61d fix BandwidthLimiterTest 2013-01-05 23:21:04 +00:00
zab
c558f5af85 Update FragmentTest to expect an IAE.
Update {Batched}FragmentTest to JUnit 4
	Use a single instance of I2PAppContext
2013-01-05 23:08:00 +00:00
zab
a33457ff7f Rename BuildMessageTest so it doesn't match the JUnit wildcard.
Add note that the test (most likely) needs to be re-written fom scratch.
2013-01-05 21:52:33 +00:00
kytv
16be8deb00 regex tidying
(fixed version of revision 5135b9e8fb88986fdc130971ebe75c3ab0665dcc)
2013-01-05 20:12:35 +00:00
kytv
dfcf1c1575 disapproval of revision '5135b9e8fb88986fdc130971ebe75c3ab0665dcc' 2013-01-05 16:22:28 +00:00
kytv
d1dc7cd269 tidy up version # regexes 2013-01-05 16:18:41 +00:00
str4d
88c2b3da58 merge of '3c30547c23e641e3cc7a7927d956997c0187aa5c'
and 'd0f6b1e4566b9690b60fa0fb686aadc3ad629a31'
2013-01-05 00:31:14 +00:00
str4d
0bfd747c95 Exclude from router cobertura anything that isn't net.i2p.* 2013-01-05 00:30:37 +00:00
zab
d150403395 Rename a non-junit test so it doesn't fall under the junit wildcard 2013-01-04 23:44:26 +00:00
zab
1939aaca93 Fix test and make it actually test something 2013-01-04 20:57:18 +00:00
zab
d0cb714f69 add installer/resources to the classpath for eclipse and junit task
do not use hardcoded filesystem path in junit test 
	(test still fails for different reason)
2013-01-04 20:17:35 +00:00
zab
54a35df9e9 merge of '3cd63a1366e2ca171fb8c348927047e0c0b7393d'
and 'a461c087d600d3fa0b5da2085d1dd97aff721d44'
2013-01-04 19:31:35 +00:00
zab
b1a29c9514 enable more output for easier debugging of tests 2013-01-04 19:28:37 +00:00
kytv
af21093012 javadoc fixes 2013-01-04 19:20:08 +00:00
zab
cea1b08a98 Update javadoc to specify non-null payload for datagrams 2013-01-04 18:46:00 +00:00
zab
c7f1329c04 get rid of two tests that don't make sense 2013-01-04 18:38:32 +00:00
kytv
a02f9313ff fix javadoc-test target 2013-01-04 02:47:10 +00:00
kytv
5a7d975ed6 speed up datahelper test (thanks zab) 2013-01-04 01:17:29 +00:00
str4d
455618dc26 merge of '9a6aaa59a51ac9c26f4a1a1a1db90feb17819a22'
and 'b5f4c5514ac1fbd9f7b61180c7874ddcac422c11'
2013-01-04 00:36:02 +00:00
str4d
bddfc5b526 Turn BuildMessageTest into a JUnit TestCase 2013-01-04 00:33:03 +00:00
zzz
bcbf7e6270 - Speed up crypto tests, reduce memory usage, use common context 2013-01-04 00:31:28 +00:00
kytv
83886cdcfb merge of '9cd70f6c6a5d8100782f92785a0082b09248e6b0'
and 'e6b29f8caf5730bada39b1296ff3eb3b5f363f0e'
2013-01-04 00:20:03 +00:00
zab
dbfb4cbbbb Remove test that does nothing anyway 2013-01-04 00:19:08 +00:00
kytv
fe477f0a0b merge of '96801f1975a618da3caa8943bc186ad78449ee94'
and 'fa2d2cb834d3792b816984bc44da70ad903e40e8'
2013-01-04 00:10:56 +00:00
str4d
dd24ab6f70 Create a new RouterContext for net.i2p.router.tunnel tests (can't cast I2PAppContext) 2013-01-04 00:07:15 +00:00
zab
47592377f2 Make test expect an UOE 2013-01-03 23:58:18 +00:00
zzz
e3ecc42e88 - Fix delivery instructions test 2013-01-03 23:13:47 +00:00
kytv
999b8d3c68 merge of '7b3e55d16589c2194327677322fca98e2ce056ad'
and '85eec7bc28af462eca4a83562771af846cb2b91c'
2013-01-03 22:58:46 +00:00
kytv
8e5c26270e cross platform unit test hostname faking not relying
on external tools

The original method failed on Archlinux. This should work everywhere.
2013-01-03 22:58:21 +00:00
zab
e67aa430cd merge of '616d36fc49bb03f28c56540cdd475e2f7e9e3663'
and '7a64fceed49d038439e050a81f45b1e6abb2ad19'
2013-01-03 22:55:56 +00:00
zab
8e57a2e386 Fix most of the test cases, reduce the runtime of the test
using LogManager.flush()
2013-01-03 22:55:40 +00:00
zzz
d28184ce72 - Test data strucure equals() for everything except I2CP 2013-01-03 22:05:10 +00:00
kytv
94827d6d55 merge of '4e4692d229faefe5a1a891b9e7e89302117d2970'
and '90cf0bde41018fcb22d53d168c8d6f56294d8660'
2013-01-03 20:12:47 +00:00
kytv
6c676869a0 change an ant 1.8ism to one supported in 1.7 2013-01-03 20:12:18 +00:00
zab
2c8f2ae404 Change the Rate.equals(..) method to work for Rates w/o a parent RateStat
Change the RateStat.equals(..) method to work with deserialized RateStats
	Update and fix the JUnit tests for both
2013-01-03 20:08:54 +00:00
kytv
3eb00c526d remove extranous reference (that I added) to junit; fix a bit more of the
router tests
2013-01-03 19:36:39 +00:00
zzz
83e25ef26c merge of '78c1ef42cf8e75cb54df7c34644855f54428565c'
and 'd37cf6a7b286442b886dbfd6f74ac948eee5b3fc'
2013-01-03 16:11:29 +00:00
zzz
8f4f7a677f - Fix junit path typo
- Fix several router unit test compile errors.
  They all compile now.
- Move SubmitMessageHistoryJob to i2p.scripts, it is not a unit test
2013-01-03 16:10:49 +00:00
kytv
b54c5f8545 renable slow tests
these tests are only slow with cobertura enabled
2013-01-03 14:15:56 +00:00
zzz
17ac0e4b5f - Fix last three I2CP message junit test failures caused by the removal of equals().
- Fix RouterAddress test failure caused by removal of expiration
2013-01-03 12:50:28 +00:00
zzz
4730690978 - Fix most of the I2CP message junit test failures caused by the removal of equals().
Still a few left where the test is overridden.
- Fix DestLookupMessage test failure caused by missing data.
2013-01-03 12:13:48 +00:00
kytv
9d77cd7761 allow setting hamcrest and junit locations with properties
Defaults to the ant library path (the previously hardcoded path) if not set.
2013-01-03 11:53:08 +00:00
kytv
5b81a1a6d5 catch unset classpath prop 2013-01-03 10:43:31 +00:00
kytv
f788ef97de remove cobertura.ser when ant clean is called 2013-01-03 02:43:51 +00:00
zzz
e4ec046363 - Add separate top-level junit.test and scalatest.test targets, so
you can run whichever you have the libs for
 - Add router to test target (if we don't run it, it won't get fixed)
2013-01-02 23:46:14 +00:00
str4d
cdc3682baa Fixes to JUnit tests under net.i2p.router.transport 2013-01-02 22:05:12 +00:00
str4d
dae66d7f73 Updated JUnit tests in net.i2p.router.tunnel - almost all bugs fixed 2013-01-02 21:29:54 +00:00
str4d
d6d1b51970 Set up build.xml test harness to run the JUnit4 tests as well
You will need junit4.jar, hamcrest-core.jar and hamcrest-library.jar in your
Ant library path (probably /usr/share/ant/lib)
2013-01-02 21:06:59 +00:00
zzz
6f301f01dc * Logs: Fix setting log filename (ticket #805) 2013-01-02 14:12:02 +00:00
zzz
71607fff2d javadoc 2013-01-02 14:02:02 +00:00
zzz
6ed602309f - Local mods and wrapper for SipHashInline
- Convert SessionTag.hashCode() to SipHash to prevent collision attacks
     in the SessionKeyManager; cache for speed
2013-01-02 14:01:29 +00:00
zzz
20cc48cd87 SipHash inline implementation and junit test, unmodified.
As pulled from https://github.com/nahi/siphash-java-inline
Last commit was 5be5c84851
2012-11-06

Copyright 2012  Hiroshi Nakamura <nahi@ruby-lang.org>
Apache 2 license

25%-35% faster than reference implementation in my tests.
2013-01-02 13:54:49 +00:00
zzz
f2331b0603 * New getASCII() for use in findbugs cleanups for 7-bit strings
This code was supplied by zab
2013-01-02 13:31:41 +00:00
zzz
8c2ddec400 add shortcut in equals() for speed 2013-01-02 13:27:24 +00:00
zzz
c8e12b9ac9 * Transport: Fix early NPE (ticket #824) 2013-01-02 13:23:23 +00:00
zzz
452d1d01b8 * SAM: Synchronize dissector 2013-01-02 13:21:45 +00:00
zzz
e375ffe8f1 * I2CP:
- Fix leak if nonce = 0 but reliability != none
   - More work on failure codes (ticket #788)
   - Fix race with _finished indication in OCMOSJ
2013-01-02 13:19:40 +00:00
zzz
2ea9fc5d61 I2CP: Remove static logs; Fix thread ID counter 2013-01-02 13:17:02 +00:00
zzz
912e29f8af - Remove unused equals() methods for I2CP message classes,
most did not have hashCode() implementations.
     These are never used as keys in a Set or Map or checked for equality.
     Fixes findbugs issues (ticket #379)
2013-01-02 13:13:35 +00:00
zzz
72054a7d30 reorder synch and loop 2013-01-02 13:08:34 +00:00
kytv
ab2c5ef9bb postinstall: delete both OSX scripts if we're not on OSX 2013-01-01 18:26:08 +00:00
kytv
ab0b4936ec refresh patch 2013-01-01 18:22:18 +00:00
kytv
2dd1aaab63 Update wrapper to v3.6.17 (ticket #826) 2013-01-01 10:39:08 +00:00
kytv
c05cd07ff7 Fixing two potential NPEs found by findbugs 2013-01-01 00:02:18 +00:00
kytv
adfc22499c Remove outdated javadoc reference & explicitly specify locale 2012-12-31 21:45:49 +00:00
kytv
44498ca8c7 installer: extra checks & add to findbugs target 2012-12-31 18:00:42 +00:00
kytv
a40566eefb improve installer javadocs; add minimalist package.html 2012-12-30 00:36:14 +00:00
zzz
77f0dd653a - Fix handling of duplicate participating tunnel IDs
- Reduce chance of generating duplicate IDs for our tunnels
   (ticket #812)
 - Stat cleanup
 - Comment out effectively unused countProactiveDrops()
2012-12-29 13:40:55 +00:00
zzz
8ed70084db catch iterator exception on java 5 2012-12-29 13:31:31 +00:00
zzz
2f4e3862e3 cleanups 2012-12-29 13:23:57 +00:00
zzz
667393e8cf * Javadocs: Fix javax links; add installer utils 2012-12-29 13:19:09 +00:00
zzz
c6dd7b4cc5 * i2psnark: Redirect after post
Button spacing on config form
2012-12-29 13:17:27 +00:00
kytv
db0501f31b explicitly specify encoding 2012-12-29 00:10:38 +00:00
kytv
3be5002f15 ant debian-tarball target: set .sh to mode 755 2012-12-28 21:17:56 +00:00
kytv
4389f277d6 * windows installer fixes / improvements
- move deprecated installer-only classes (Exec, Delete, and Copy) from
    i2p.jar into installer/
  - replace installer/resources/fixpaths.cmd with an improved method in java
  - combine the installer-only utility classes into a single jar and call the
    classes from within izpack
2012-12-28 20:59:17 +00:00
str4d
cf10cb1c09 Fixed out-of-date references to wrapper.jar and jbigi.jar so that the justBOB target works 2012-12-27 11:59:48 +00:00
zzz
38214cf5be * I2CP:
- Prep for delivery of detailed failure codes to the client (ticket #788)
   - Store session ID as an int instead of a long
   - Clean up some duplicate createRateStat calls (ticket #787 comment 2)
   - Other optimizations, cleanups, final
2012-12-26 14:29:49 +00:00
zzz
f4740d2639 * Stats: Clean up some duplicate createRateStat calls (ticket #787 comment 2) 2012-12-26 14:22:30 +00:00
zzz
48309c0f6d * NetDB: Split routerInfo files into subdirectories, disabled for now,
enable with router.networkDatabase.flat=false
2012-12-26 14:19:52 +00:00
zzz
cf1f42ebf8 * Tunnels: Catch rare BuildExecutor IAE only in Java 7 (ticket #811) 2012-12-26 14:16:49 +00:00
zzz
7c8bb0ba69 comment out main 2012-12-26 14:15:19 +00:00
zzz
14eedaa029 * i2psnark: Create torrent form tweaks 2012-12-26 14:14:43 +00:00
kytv
73e25aad76 * Add EOL modifications
- set eol for certain files in installer targets (since editing *.config and *.xml in windows is practically impossible without an externally installed editor such as vim or notepad++ and of course we want people to be able to read the licenses if they desire...etc.)
  - try to prevent user error by ensuring that the proxy/*.ht files have eol set to crlf in the prepConsoleDocs target
2012-12-25 00:13:32 +00:00
kytv
f3f4529d84 use ant features instead of Unix commands where possible in the installer2app target. Also make izpack2app a settable property 2012-12-24 22:09:10 +00:00
kytv
5dbe6294fb debian-binary: don't assume that noAutoDebchange will be set by people that know that debian/changelog needs to be set 2012-12-24 19:55:16 +00:00
kytv
91c9bfed3a add additional arm types to the 'noExe' condition & add reference the cybergarage javadocs revision in history.txt 2012-12-24 19:46:40 +00:00
kytv
420ccad91b javadoc fixes for the upstream cybergarage UPnP library. Upstream ticket #3598391 has been filed for this issue. 2012-12-24 19:44:25 +00:00
kytv
1d0f8b4c6d Add missing shebang lines to bundle-messages scripts 2012-12-23 17:35:07 +00:00
kytv
3396626a0c * new ant targets
- trimMtnRev: create a new property with the revision trimmed to  8 characters.
  - getExtendedVersion: create a new property that includes the full version with the shortened MTN revision tacked on
  - debchange:  automatically update debian/changelog with the I2P version. Called by the "debian" target unless the property noAutoDebchange is set.
  - debian-tarball: export i2p.i2p branch to a new directory, remove the binaries like jbigi and launch4j, and create a tarball.
* move packages created by "ant debian" to ${basedir}
* add debian/changelog to .mtn-ignore since it is now automatically updated (by default).
* add *.deb to .mtn-ignore
2012-12-23 17:30:56 +00:00
kytv
8c13d32036 debian: add repack script and update watch file to use repack.sh 2012-12-23 17:20:15 +00:00
zzz
5d523723ed merge of '2e3c8b51430edfa3ce0e82bc4b49ea7c21c0606b'
and 'c643595f81605fc5534465da3f1655e4c23345a1'
2012-12-22 19:59:06 +00:00
zzz
6d2fa690dc quoting fixups 2012-12-22 19:30:36 +00:00
zzz
470b8c59e7 minor console/update cleanups 2012-12-22 18:37:26 +00:00
zzz
81975e919b propagate from branch 'i2p.i2p.zzz.test2' (head f33dbe1499b84cf6192b1a7bd494eaf081a047c0)
to branch 'i2p.i2p' (head 4e5bd2836592b95e1eff01d8e83f2690da386ef8)
2012-12-22 18:34:51 +00:00
zzz
436d8f0785 - Add support for announce-list (BEP 12) to TrackerClient (ticket #778)
- Refactor dup tracker detection
2012-12-22 18:05:42 +00:00
kytv
fa235d97af enable i2prouter translations in the debian package & refresh patch 2012-12-22 17:51:15 +00:00
kytv
42f8c71d4e update .mtn-ignore 2012-12-22 17:50:46 +00:00
kytv
9a241af241 enable translations for 'i2prouter' 2012-12-22 15:10:57 +00:00
kytv
69d22b84f9 i2prouter: integrate modifications from upstream (Tanuki) 2012-12-22 14:57:28 +00:00
zzz
7ea1bffea2 rename Tracker class for clarity 2012-12-22 14:13:16 +00:00
kytv
c1f4155cd8 French language update from transifex + updated EN po files that were uploaded to transifex 2012-12-21 23:50:08 +00:00
kytv
85fda3ed7f minor regex tweak 2012-12-21 21:17:33 +00:00
kytv
8998bdec17 remove another reliance on external UNIX-only tools (and fixing formatting of my earlier commit) 2012-12-21 21:13:31 +00:00
kytv
c9b6a3f01c Instead of deleting the empty directory placeholders, let's just not copy them to pkg-temp to begin with. 2012-12-21 20:53:51 +00:00
kytv
05c5f66012 fix my getBuildNumber regex 2012-12-21 20:46:02 +00:00
kytv
7fd59c4f10 add more excludes to 'sloccount.report' and make the report location configurable 2012-12-21 20:45:05 +00:00
kytv
6fe127286f add armv6 and armv7 to the "do not build EXE" list 2012-12-20 07:25:28 +00:00
kytv
406bcbef9d remove dependencies on external tools for getReleaseNumber and getBuildNumber
getReleaseNumber and getBuildNumber were *NIX only targets that relied on the external tools grep, cut, awk, and tr. These targets have been rewritten to use ant features.
2012-12-20 07:23:01 +00:00
kytv
9eb25f60c3 add sloccount report target 2012-12-20 07:16:39 +00:00
kytv
b7c10d2adb remove a few more files with "ant clean" 2012-12-20 07:13:26 +00:00
kytv
816149efd3 debian: refresh patches 2012-12-19 21:31:02 +00:00
kytv
aa6eefcc76 debian: add commented entries required for PPA builds & update "debianhowto" target
If someone runs "ant debian" to make installable packages, they do not need to
have their own wrapper or commons-logging  jars. The PPA builds, however, do
require them. During the last release I made the mistake of overwriting my "PPA
debian/control" file with the one from MTN that did not include these
dependencies.

Also updating "debianhowto" to reflect the fact that we no longer use
Debian's/Ubuntu's Jetty pkgs since Jetty6 appears to be leaving their repos in
the near future.
2012-12-19 21:25:04 +00:00
kytv
9ef9e48da9 remove executable bit 2012-12-19 21:09:17 +00:00
kytv
166e36aaef move taskdefs to targets
The directory installer/lib/ will be removed if a 'stripped' source tarball is
required. Without the changes in this commit, removing this directory will
require hackery to be performed on the I2P source in order for any of the ant
targets to work.
2012-12-19 21:08:57 +00:00
zzz
667b548d3b * Update: Hide the update buttons when router.updateDisabled=true, as is the case
for Debian packages. Broken in 0.9.4. (Ticket #817)
           Remove unused shouldInstall() method.
2012-12-19 14:58:37 +00:00
kytv
5dfef69688 Add dummy placeholder files to empty eepsite directories
git and a few other vcses don't store empty directories....but now these directories
are no longer empty.
2012-12-18 20:50:29 +00:00
zzz
c3ae3f2895 build fix 2012-12-17 15:29:26 +00:00
zzz
8b41956091 0.9.4 2012-12-17 14:52:02 +00:00
str4d
264e27ab3f Correct url for forum.i2p 2012-12-16 03:23:16 +00:00
zzz
74f6abc97a bump 2012-12-15 14:54:32 +00:00
zzz
8edbfc5198 replace call to Arrays.copyOf(), not in Java 5 2012-12-15 14:41:42 +00:00
kytv
8513d1f22b merge of '482fcb3afd2e52160588dbf9e253ff594e0d5ce3'
and 'a63132b861cf363158a5ac2e1897b4636321d536'
2012-12-15 00:37:09 +00:00
str4d
cb75e3dc7e Documented required and optional test-related properties in build.properties 2012-12-14 22:33:37 +00:00
kytv
a8926dae57 ship all of the *BSD jcpuid files in the installer 2012-12-14 22:20:20 +00:00
kytv
c5502737f2 Debian: changelog and minor initscript updates 2012-12-14 16:14:46 +00:00
kytv
206cea8b56 update geoip.txt
Update geoip.txt based on Maxmind GeoLite Country database from 2012-12-04
2012-12-14 16:00:09 +00:00
kytv
003a8b07e1 German and Swedish translation updates from Transifex 2012-12-14 15:58:59 +00:00
zab
c5d69eb231 jenkins test passed! 2012-12-14 08:34:27 +00:00
zab
78864ab380 test to see if the jenkins server by skydrome detects broken compilation 2012-12-14 08:29:08 +00:00
zzz
ec22a6ec6b copy armv6 wrapper in preppkg-linux target 2012-12-13 12:33:53 +00:00
kytv
b435857e15 don't try to copy armv7 wrapper in preppkg-linux target 2012-12-12 20:34:37 +00:00
zzz
8198419156 build fixup 2012-12-12 15:43:42 +00:00
zzz
60718dbf72 Drop custom-built armv7 wrapper.
Tanuki-built arm wrapper works on armv5 and armv7 but not on Raspberry Pi armv6.
Wrapper we built for Raspberry Pi does not work on Trimslice armv7.
2012-12-11 19:27:56 +00:00
zzz
4e558320a9 - i2psnark: Add announce list support (BEP 12) (ticket #778)
Preliminary. Still todo: TrackerClient
2012-12-10 22:48:44 +00:00
zab
1fa00a5738 Restore javadocs 2012-12-10 18:05:52 +00:00
zzz
9f6ebd8e10 longer tunnel options for servers; fix spacing issue 2012-12-10 17:39:02 +00:00
zzz
c4a0fcbf43 propagate from branch 'i2p.i2p' (head 99b582d7fcc9d377341809a5fe580b439b37fea6)
to branch 'i2p.i2p.zzz.test2' (head f620dc8ce09657b3bfe0d87b5ee09c1bc33c31d1)
2012-12-10 17:23:29 +00:00
zzz
8104cb40cd Apache Tomcat 6.0.36 2012-12-10 17:23:07 +00:00
zab
d2b2600e5e VersionComparator w/o object churn, ticket #789
tests
2012-12-10 10:07:34 +00:00
zab
d062db3c17 Object churn improvements, ticket #787 2012-12-10 09:46:05 +00:00
zab
32a8bb7a3e more VersionComparator tests 2012-12-09 16:59:51 +00:00
zab
d8417cbf71 more tests for VersionComparator 2012-12-09 13:28:06 +00:00
zzz
863a05b33d * susimail: Button CSS spacing tweak 2012-12-08 12:12:29 +00:00
str4d
3fc3abe7a5 Moved susimail.properties out of the build path, and set build.xml to copy it in 2012-12-08 02:02:04 +00:00
zzz
96fcaf9385 javadoc 2012-12-07 14:21:30 +00:00
zzz
0b14981163 fix forum urls 2012-12-07 14:20:43 +00:00
zzz
87a56a6fac * RouterClock: Reduce log level (ticket #790) 2012-12-07 14:20:02 +00:00
str4d
0fa938e096 merge of '60726592fdfe50d6d8051846e0034b4b40a6761e'
and 'ad92f5811a7ff6ceab5ab09572d716f00f9100ea'
2012-12-06 00:17:13 +00:00
meeh
b7e3a60fbc Ticket #802
Added https://euve5653.vserver.de/netDb/ to reseed host list.
Certificate using www.cacert.org, so no need to add a new crt file.
2012-12-05 20:57:33 +00:00
kytv
653ccaae49 typo fix + updated UK translation 2012-12-05 14:38:56 +00:00
zzz
ca00b34314 * I2CP: Fix external I2CP apps, including i2ping, caused by 0 nonce value,
broken in 0.9.2 (tickets #799, #801). Allow nonces == 0.
   Javadocs and cleanups.
2012-12-05 00:03:27 +00:00
zzz
0c5811801f * SSU: Fix rare NPE (ticket #798) 2012-12-05 00:01:49 +00:00
zzz
d9727c901c * Reseed: Don't go on to the next host if we have enough http://zzz.i2p/topics/1287 2012-12-05 00:00:55 +00:00
zzz
63b8e7101f * GarlicMessage: Fix notes and log in GarlicMessageHandler and HandleGarlicMessageJob,
they are used for netdb messages received by floodfills http://zzz.i2p/topics/1282
2012-12-05 00:00:06 +00:00
kytv
4f5da775d4 Chinese, French, Italian, Polish, and Ukrainian translation updates from
Transifex.
2012-11-28 23:27:16 +00:00
kytv
3464ad6e5e remove extraneous space 2012-11-28 19:39:31 +00:00
kytv
d28480dd92 bumping build to -12 2012-11-28 10:34:19 +00:00
kytv
4902b4ecba merge of '32a936bfa4c9048f8d96461990da03f7f35cb676'
and '9c7cae316969219b1f2d74c20dbb4a12a94857a9'
2012-11-28 10:28:30 +00:00
zab
0e0a38460e Revert to using ArrayList in RouterInfo 2012-11-28 08:19:34 +00:00
str4d
4266a10ffb Added more tests to VersionComparatorSpec to further cover the implementation 2012-11-26 00:29:02 +00:00
str4d
31fc55eca7 Added tests for VersionComparator 2012-11-25 02:44:01 +00:00
str4d
4d389f75a2 Changed summary bar ordering <input type="image">s to <button>s
Fixes a bug which caused the ordering to be non-functional.
2012-11-25 02:39:49 +00:00
zzz
abe29e044f Remove org.mortbay.http.Version.paranoid property not recognized by Jetty 6. 2012-11-24 20:01:07 +00:00
zzz
8d2eff76f2 fix jetty system properties 2012-11-24 19:56:58 +00:00
zzz
c5a6ed3179 final 2012-11-24 17:30:20 +00:00
zzz
99058ee135 * Codel: Make stats non-required (ticket #786) 2012-11-24 16:41:55 +00:00
zzz
b2e335fbba * Profiles: Small optimization in coalesceOnly() (ticket #765)
javadoc, detab
2012-11-24 16:41:12 +00:00
zzz
1d3bbfd250 * Addressbook: Disable unused wakeup via http 2012-11-24 13:56:45 +00:00
zzz
916e328e10 javadoc, volatile 2012-11-24 13:55:47 +00:00
zzz
fe02145fed typo 2012-11-24 13:53:12 +00:00
str4d
ad41b25be5 merge of '138eae0135999a3f8e20b08183500a2318287cd4'
and '314f5c9d4fc6b5dd82d6ee09a207686f52e66a2c'
2012-11-23 20:12:11 +00:00
str4d
d2b1103e26 Removed a hard-coded jsp link I missed 2012-11-23 20:10:52 +00:00
kytv
0b05cd761c i2prouter: fix block location (thanks k0e) 2012-11-23 18:08:04 +00:00
kytv
28ba7880e4 merge of '15d44385349738e5c84f8efcdb797d98b4fbaed0'
and '586f7a71f1e187cb041d873c013fbe91d0184b08'
2012-11-23 18:07:07 +00:00
str4d
4680fd118b Added remaining .project and .classpath files
The project files for jetty are in the apps/jetty folder. Dependencies will be
resolved once the project has been built normally once via e.g. "ant updater".
2012-11-23 12:31:02 +00:00
str4d
9dcfe98437 Added .project and .classpath Eclipse files to most sections of the source
To import a branch of trunk into Eclipse, create a new workspace based in the
root directory of the checked-out branch, and then select "File -> Import..."
then "General -> Existing Projects into Workspace", then for "Select root
directory" choose the root directory of the branch (and of the workspace).
Select all projects that appear, so that dependencies are satisfied.

Currently left out are i2psnark, routerconsole and susimail, because they all
depend on jars in apps/jetty/jettylib, which seems to be auto-generated. Need
to check whether the existence of that folder (from having Eclipse files in it)
will prevent the jars being populated or not.
2012-11-23 12:20:26 +00:00
zab
55c264916b kill a string allocation hotspot 2012-11-23 07:52:03 +00:00
zab
0ec77f5514 Use the cached iterator list to remove Iterator allocation hotspots 2012-11-23 07:22:58 +00:00
zab
f238d0514f test removal 2012-11-23 07:13:21 +00:00
zab
d8613d2285 more appropriate junit test 2012-11-23 07:06:01 +00:00
zzz
009b0bfdde more empty jars not to pack 2012-11-23 01:30:48 +00:00
zzz
924963eba0 fix class cast exception 2012-11-22 23:14:08 +00:00
zzz
de175b80fe updates 2012-11-22 22:54:11 +00:00
zab
1e83028702 An ArrayList that reuses a single iterator 2012-11-22 21:50:48 +00:00
zzz
9fc7258537 - Update non-default xml files
- Update DTD
2012-11-22 21:42:15 +00:00
zzz
50df4b53db - Clean up WebAppconfiguration
- Fix eepsite xml files
- First cut at updating migration code (untested)
2012-11-22 21:17:50 +00:00
zab
e974d3bc55 propagate from branch 'i2p.i2p.zab.782' (head 64415601890b9c494a8f06379f9feefbc855e07c)
to branch 'i2p.i2p' (head 0e92cf3a3844e7b738ca9c2486112867fc663b6f)
2012-11-22 20:53:03 +00:00
zab
7c96044d18 javadoc 2012-11-22 20:47:54 +00:00
zzz
d5d70f1b40 Wrapper 3.5.16 compiled on Raspberry Pi:
GPLv2
binaries stripped

gcc (Debian 4.6.3-12+rpi1) 4.6.3

java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.5) (6b24-1.11.5-1+rpi1)
OpenJDK Zero VM (build 20.0-b12, mixed mode)

Processor	: ARMv6-compatible processor rev 7 (v6l)
BogoMIPS	: 697.95
Features	: swp half thumb fastmult vfp edsp java tls 
CPU implementer	: 0x41
CPU architecture: 7
CPU variant	: 0x0
CPU part	: 0xb76
CPU revision	: 7

Hardware	: BCM2708
Revision	: 0002
2012-11-22 00:36:45 +00:00
zzz
02ad4d5200 fix NPE 2012-11-21 22:53:22 +00:00
zzz
56ae54c2ff Jetty 7 license info copied from jetty-distribution-7.6.8.v20121106 2012-11-21 22:20:05 +00:00
zzz
a70e040e33 susimail compile fixes for Jetty 7.
Untested.
2012-11-21 21:21:38 +00:00
zzz
c0d82fe83f i2psnark compile fixes for Jetty 7.
Untested.
2012-11-21 21:09:31 +00:00
kytv
34e0b36401 updates to 'i2prouter' based on changes to Tanuki's example script 2012-11-21 21:03:55 +00:00
kytv
2fbe0e8bb1 update wrapper to v3.5.16
- Windows: Self-compiled with VS2010 in Windows 7. The icon has been
  changed from Tanuki's default to Itoopie.
- FreeBSD: Self-compiled in FreeBSD 7.4 to eliminate the dependency on the
  compat6x port and stripped.
- Linux PPC32: Self-compiled in Debian Squeeze and stripped
- Linux x86, Linux x64, Linux ARMv5, MacOSX & Solaris: Binares are from the
  "community edition" deltapack offered by Tanuki. The Linux binaries have
  been stripped.
2012-11-21 21:01:45 +00:00
zzz
f1dd77982a RouterConsole compile fixes for Jetty 7.
Convert LocaleWebAppHandler from extending WebAppContext to
extending HandlerWrapper, since handle() is now final in WebAppContext.
Untested.
2012-11-21 20:49:18 +00:00
zzz
be8697cb9a jetty 7 first cut 2012-11-21 18:05:50 +00:00
zab
33ee8a38ca Ticket #765 - optimize locking during profile reorg 2012-11-21 15:45:38 +00:00
zzz
5f4562467e * Transport: Fix bug that inadvertently reduced default max
SSU connections in 0.9.2, cutting network capacity in half and
   harming tunnel build success rates
2012-11-20 01:17:02 +00:00
kytv
56ef4cda82 Addi an exception for core2 & corei to NBI on 32-bit kFreeBSD, NetBSD, and OpenBSD
These binaries are identical on 32-bit kFreeBSD, NetBSD, and OpenBSD systems.
If a corei CPU is found on these systems we'll use the core2 jbigi binary.

194868,ad47c3d909d0fb85242566f3c7b4be5b,libjbigi-kfreebsd-core2.so
194868,ad47c3d909d0fb85242566f3c7b4be5b,libjbigi-kfreebsd-corei.so
202848,57aa013ca310f3aae990f5ee78c100bd,libjbigi-netbsd-core2.so
202848,57aa013ca310f3aae990f5ee78c100bd,libjbigi-netbsd-corei.so
207657,01483211b6e077057302e256f185f7e7,libjbigi-openbsd-core2.so
207657,01483211b6e077057302e256f185f7e7,libjbigi-openbsd-corei.so

The I2P project does not currently ship these binaries, but they can be found
in unofficial jbigi packages.
2012-11-19 23:47:55 +00:00
kytv
5975b69b42 Add jcpuid binaries for OpenBSD, NetBSD, and kFreeBSD.
Support for these has already been added to CPUID.java.
2012-11-19 22:44:58 +00:00
kytv
d0a3c7256a Improved support for GNU/kFreeBSD
- add kFreeBSD to NBI and CPUID
- add kFreeBSD to jcpuid/jbigi build scripts
- refresh debian patches to compensate for kFreeBSD changes
- i2prouter: Detect kFreeBSD and normalize its name
- clean up osid (switching to "elif") and adding support for detecting kFreeBSD
- update postinstall.sh; I2P cannot be installed using gij so postinstall.sh
  will not be run. If/when openjdk finally comes to kFreeBSD, we'll be ready for it.
2012-11-19 22:41:54 +00:00
zzz
d94c14967c move HashDistance to router/util 2012-11-19 16:22:09 +00:00
zzz
f15828fa95 * NetDB: Add negative lookup cache 2012-11-19 16:10:02 +00:00
zzz
f64eacefe3 * BuildHandler: Disable CoDel, wasn't helping 2012-11-19 16:06:59 +00:00
zzz
c8f2effca8 * Profiles: Split up files into subdirectories 2012-11-19 16:04:33 +00:00
kytv
74f4859e13 explicitly prefer openjdk-*-headless over default-jre-headless.
On Debian Squeeze the default-jre-* packages point to gij/gcj which is suboptimal.
Openjdk cannot be forced since not all platforms--such as kFreeBSD--have it as
an available option.
2012-11-18 18:52:13 +00:00
zab
8c987fc0d2 Add javadocs to getters
Make setters package-private
	Small noop tweak to the computeAverages
2012-11-18 15:01:43 +00:00
zab
efc202d2ee more use of the new methods 2012-11-17 19:22:23 +00:00
zab
3cbca7c0ac more use of the computeAverages method 2012-11-17 18:51:28 +00:00
zab
82e4244473 more refactoring 2012-11-17 18:36:55 +00:00
zab
836620c375 javadoc 2012-11-17 18:03:10 +00:00
zzz
addfff8626 * Tunnels: Set default priorities for tunnels (ticket #719)
Exploratory: +30
   IRC: +15
   HTTP Proxy: +10
   I2PSnark: -10
2012-11-17 17:32:24 +00:00
zzz
3836742e7d stat cleanup 2012-11-17 17:24:44 +00:00
zzz
74fd171131 * i2psnark: Clear PEX peers set after use, cause of bad peer counts 2012-11-17 17:11:39 +00:00
zzz
d511bf2cd8 * error500.jsp: Add servlet version 2012-11-17 17:10:31 +00:00
zzz
0cbbedd250 javadoc fix 2012-11-17 17:09:37 +00:00
zab
4824cae36c Properly synchronize the Rate class
Add a new class to store results from rate calculations
	Add a new method to compute average, last and current measurements
	Use the new method in RouterThrottleImpl
2012-11-17 00:04:08 +00:00
kytv
b67359aca6 Match *FreeBSD* instead of just FreeBSD*.
(spotted at http://pastethis.i2p/show/2280/ and jcpuid already matches
*FreeBSD* so this fixes a minor consistency issue. Thanks to the anonymous
paster.)
2012-11-16 21:24:03 +00:00
zzz
99179edae2 add reseed to event log 2012-11-16 15:33:38 +00:00
zzz
ae6dad6e48 * NetDB:
- Implement automatic reseeding (ticket #521)
   - Increase minimum routers from 15 to 50
2012-11-16 14:47:55 +00:00
zzz
6902a8392f * i2psnark: Fix rare IOOBE (ticket #777) 2012-11-16 14:45:05 +00:00
zzz
4991c5a1ad * Tunnels: Fix outbound tunnel message priority (ticket #719)
(copy/paste error)
2012-11-16 14:43:46 +00:00
zab
a3e3001d49 * Sync fixes to Frequency
* Removal of warnings related to generics in StatManager
2012-11-14 21:53:54 +00:00
zzz
4fdf1c2411 * stats.jsp: Link to graph page, not single image 2012-11-13 20:40:15 +00:00
zzz
ea00c0af50 * SSU: Fix bug that would drop 512 byte messages
The bug has been there forever but never happened before
   0.9.3 because the buffers were all 32KB and the largest
   fragment was about 1500 bytes. In 0.9.3, there are multiple
   buffer sizes, the smallest is 512 bytes, and a packet
   of exactly 512 bytes would be silently dropped.
   Thanks zab for finding it.
2012-11-13 20:39:29 +00:00
zzz
e6dbd7ddda * SOCKS: Reduce log level of connect errors 2012-11-13 20:36:42 +00:00
zzz
9741d127a9 * NTCP:
- Fix NPE with more syncing (hopefully) (ticket #770)
   - Use ByteCache for 16KB buffers
2012-11-13 20:35:47 +00:00
zzz
8efc7e9369 * HTTP Proxy: Store referrer of new addresses in address book 2012-11-13 20:33:37 +00:00
zzz
da009f8d22 * Bandwidth Limiter: Fix stats broken in -1 2012-11-13 20:32:39 +00:00
zzz
f8133b7abf log tweak 2012-11-13 20:30:56 +00:00
kytv
2362862f31 eepget: If java binary is not found, try to determine where java.exe is located.
In my testing:
32 bit Windows (and, of course, 32 bit JRE) = Java added to the PATH
64 bit Windows and 64 bit JRE = Java added to the PATH
64 bit Windows and 32 bit JRE = Java *not* added to the PATH.

So...with this check-in:

- If the environment variable JAVA is set in the script, we'll use that
  manually specified Java. We will not look in the registry, but we'll check to
  make sure that the binary exists.
- If Java is found in the system path, we'll use it instead. We will not look in the
  registry.
- If the variable is not set manually and Java is not in the system path we'll
  look in the registry to find the java binary.

I've tested this in Windows XP, Vista, and 7 but it should work in any supported version
of Windows.
2012-11-09 23:53:02 +00:00
str4d
f287ed48ed merge of '6f719ac61e6f1afbd935f3fdab862c2e5cc7f5d8'
and 'fd3c457f0a834ba87fead3cbdf22e31253cd4e7c'
2012-11-07 19:29:34 +00:00
meeh
b8a9caeb4c Cleanup in reseed list, also removed HH's ssl host, since it expires 21-11-2012 22:34:10 GMT+1. And
I've failed to get in contact with him for a renewal of his certificate. Errors might appear in logs 
on installs after that date, just remove https://euve5653.vserver.de from /configreseed in console 
and you wont get errors.
2012-11-06 22:00:00 +00:00
str4d
dccd8445e6 More changes to finish first test in UpdateBehaviors 2012-11-06 11:23:57 +00:00
str4d
c5fb009c83 merge of 'd09201283ea0356bf5b1d3aedc4795a202414930'
and 'e2f50f8cb50f8593ca882e94cb661c54b87d2468'
2012-11-05 21:40:35 +00:00
str4d
4d8973b0a5 Assorted fixes to router Junit tests for changes in the source 2012-11-05 21:31:40 +00:00
str4d
f57d91ac16 Added missing DateAndFlagsTest - no errors in core junit tests now 2012-11-05 21:00:20 +00:00
str4d
ccc5923ab3 Drop unused DummyPooledRandomSource, moved to i2p.scripts 2012-11-05 20:43:47 +00:00
str4d
31debe6bbf CryptixRijndael_Algorithm._BLOCK_SIZE is private, so specify value directly 2012-11-05 19:53:00 +00:00
str4d
40d1507237 Fixed imports on core JUnit tests to use Hamcrest matchers provided with Junit4 2012-11-05 19:50:32 +00:00
zzz
ea2be02a29 * RequestLeaseSetJob: Only disconnect client after multiple dropped
lease set requests; reduce timeout, other cleanups
2012-11-05 17:23:32 +00:00
zzz
c21a6a54f8 * PeerManager: Don't reorganize as often if it takes too long (ticket #765) 2012-11-05 17:20:47 +00:00
zzz
70a2e330ef * i2psnark:
- More DHT limits
   - Announce to backup trackers if DHT is empty
   - Use PEX and DHT info in torrent peer count
   - Don't use temp files for announces
   - TrackerClient refactoring
   - cleanups
2012-11-05 17:20:07 +00:00
zzz
d5c70676b0 * Console:
- Fix NPE after restart (ticket #763)
   - Move more nonces out of system properties
2012-11-05 17:17:31 +00:00
zzz
202c92a42d * Unsigned Update: Fix notification on failure 2012-11-05 17:16:02 +00:00
str4d
3cb4d35cee propagate from branch 'i2p.i2p.zzz.update' (head 1ca3b931ebecd4ec80e7e135b634d085934c092b)
to branch 'i2p.i2p' (head c917793878189c29441f69133e029cfdfe3c0895)
2012-11-05 10:38:54 +00:00
str4d
3d35984cf5 Started filling out UpdaterBehaviors 2012-11-05 10:37:18 +00:00
str4d
2217d1ab95 Moved *streaming and i2ptunnel tests to match convention 2012-11-04 11:23:12 +00:00
kytv
75ddc12390 de, pt, and se updates from Transifex. Updated en po files to push to tx. 2012-11-02 19:54:49 +00:00
zzz
d48fab9d98 * I2CP:
- Better fix for logging dropped messages (ticket #758)
   - Implement fast receive to reduce per-message handshakes
   - Make messageReliability=none the default
2012-11-02 16:37:23 +00:00
zzz
d30aeb3902 * KeyManager: Eliminate races, buffer I/O, eliminate periodic syncing 2012-11-02 16:01:44 +00:00
zzz
d479c4ae7d * configstats: Fix group sorting, translate groups 2012-11-02 16:00:41 +00:00
zzz
9c220e08f8 * i2ptunnel:
- Better privkey backup file name
   - Revert increment of privkey tunnel name
   - Move deleted privkeys to backup dir
   - Fix jsp build dependencies
   - Fix layout issue on Chrome (ticket #757)
2012-11-02 15:59:51 +00:00
zzz
eee38a626d * i2psnark:
- Split buckets correctly
   - More exploration fixes
2012-11-02 15:58:26 +00:00
zzz
f29a45a2c2 * PriBlockingQueue: Enforce max size 2012-10-31 16:15:32 +00:00
zzz
a5b68d4fb0 * I2CP: Reduce log level when outbound queue is full (ticket #758) 2012-10-31 16:09:28 +00:00
zzz
8a7d119962 * FIFOBandwidthRefiller: Reduce refill interval to smooth output 2012-10-31 16:07:11 +00:00
zzz
84a0793a10 * Streaming: New disableRejectLogging option (default false), enable for snark 2012-10-31 15:56:02 +00:00
zzz
2f4eeda397 * i2ptunnel: Fix NPE in zzzot plugin 2012-10-31 15:53:57 +00:00
zzz
96ed7abdc5 javadoc, final, private, volatile 2012-10-31 15:52:12 +00:00
str4d
6a91918e6f Stubbed out Specs for net.i2p.router.update.* in routerconsole
*Behaviors.scala should really go in net.i2p.update.* in core, but ScalaTest
doesn't seem to be picking up the cross-dependency properly and just ignores
any Spec which includes them; they will move once the build.xml is fixed.
2012-10-31 00:22:15 +00:00
kytv
2c3edc0503 merge of '2b4768d9966695ad845dad4e28ef426d781e718f'
and '8489000cfeee5a6aa5a250b48bda4f6e2fb16b03'
2012-10-30 19:41:47 +00:00
kytv
f6bac8a08e redirect output to /dev/null (in case /proc/1/comm doesn't exist) 2012-10-30 19:41:35 +00:00
zzz
4ce11a174a * SSU:
- Adjust RTT/RTO calculations
   - Better bandwidth tracking
   - Cleanup of OutboundMessageState
   - Stat tweaks
 * Transports: Increase min peer port to 1024
2012-10-30 18:16:37 +00:00
zzz
d92f5e6508 merge of 'b2b4c1ba1f799d81d6d164698cb28aa9b837d390'
and 'c2b60a59c73835b51357a706da377862d8bd5ebc'
2012-10-30 15:06:38 +00:00
zzz
513821123e remove space in javascript urls 2012-10-30 13:18:54 +00:00
sponge
f56c804e86 cleanups as requested 2012-10-30 11:03:11 +00:00
meeh
fb50f7adb4 Adding two new reseed hosts. Thanks to h2ik and SWAT
* reseed.info - SWAT
* i2p.feared.eu - h2ik
2012-10-30 02:27:16 +00:00
str4d
a99bf60cea Added Mockito to ScalaTest classpath, and removed unneeded entry
Put mockito-all.jar (or a link to the actual version) in the same directory
as the ScalaTest lib files (passed in the command line as scalatest.libs).
2012-10-29 22:30:53 +00:00
zzz
40d981df25 * OutNetMessage: Properly clean up when dropped by codel (but unused for now
since codel is disabled for ONM)
 * Tunnels: Implement per-client outbound tunnel message priority (ticket #719)
 * ClientTunnelSettings cleanup
2012-10-29 22:21:50 +00:00
zzz
f5165cfae5 log tweak 2012-10-29 22:17:38 +00:00
zzz
055bae0450 * StatisticsManager: Publish stats less often 2012-10-29 22:16:29 +00:00
zzz
74e5ea6e20 * Installer: Drop news.xml and old certs 2012-10-29 22:12:30 +00:00
zzz
32f3ca0568 * logs.jsp:
- Don't display dup message if last
   - Spacing tweaks
2012-10-29 22:10:42 +00:00
zzz
fd3423fe09 * i2ptunnel:
- Create backup privkey files (ticket #752)
   - Fix NPE in Android startup
2012-10-29 22:09:55 +00:00
zzz
05d299816b * i2psnark:
- Add kbucket debugging
   - Eliminate redundant explore keys
   - Add more limits to DHT tracker
   - Delay expiration at startup
   - Only enable updates for dev builds and 1% of release builds
 * Update Manager: Warn on dup registration
2012-10-29 22:08:38 +00:00
zzz
2b80d450fa drop old fortuna build script 2012-10-29 22:06:03 +00:00
str4d
9a31115eff Classpath change in router build.xml to get routerconsole test harness to work 2012-10-29 12:14:04 +00:00
zzz
4baf3b6913 Fixups after props from:
i2p.i2p.zzz.pcap
	i2p.i2p.zzz.test
	i2p.i2p.zzz.test2
	i2p.i2p.zzz.update
Javadoc fixes
Checklist tweak
-1
2012-10-28 13:08:02 +00:00
zzz
5e48331eae propagate from branch 'i2p.i2p.zzz.update' (head 267311f29e501fcc8b3d674a93e78b5520ac985e)
to branch 'i2p.i2p' (head edeca2ab47e734c2314ff394609292d8bd3d5293)
2012-10-28 12:48:35 +00:00
zzz
5766db2c09 propagate from branch 'i2p.i2p.zzz.pcap' (head fff5fc864e5905ed77f8d60f7d0892ed5c2447b4)
to branch 'i2p.i2p' (head cc74e6e08096cc7fdb8563b2eae82df2a000ab01)
2012-10-28 12:26:52 +00:00
zzz
c4f6f48eeb propagate from branch 'i2p.i2p.zzz.test2' (head a002e8957b5bf3a44149203d6842ef4b35107aa7)
to branch 'i2p.i2p' (head 0f6e2b3b8643fe7797e8727329345c1ed4cf741b)
2012-10-28 12:24:07 +00:00
zzz
943e2d7fe7 propagate from branch 'i2p.i2p.zzz.test' (head 48448fc896d1e0859f481e98d0e80e764cc40736)
to branch 'i2p.i2p' (head aedb9b8335d6de72dd633e79716fff6ffec263a1)
2012-10-28 12:17:38 +00:00
zzz
c4fa8fabb2 - Continue work to use priorities in FIFOBandwidthLimiter
- Log tweaks
2012-10-28 12:10:24 +00:00
zzz
6868047ee4 * i2ptunnel:
- Refactor TCG to use ClientApp interface
  - Remove 'reload config' button
  - Synchronization fixes
  - Don't instantiate early, to allow router to hold
    a reference. TCG.getInstance() may now
    return null when in RouterContext.
  - Jsps display message when TCG not initialized
2012-10-27 18:51:50 +00:00
zzz
80e7ee46fb enable pw when adding one 2012-10-27 18:45:16 +00:00
zzz
61ee957add pcap:
- Buffer output
 - Separate methods for inbound and outbound, so we
   don't need to use PacketLocal for inbound
 - Cleanups after prop
 - Finals etc.
2012-10-27 18:03:54 +00:00
kytv
6e66d377f6 changelog/patch updates 2012-10-27 18:00:10 +00:00
zzz
99e759a5be propagate from branch 'i2p.i2p' (head 6e6de141ddbaddfcecf8a66ad8cf65f247f41f94)
to branch 'i2p.i2p.zzz.pcap' (head ae8977bcc33f75ee36505e739e9e4a194f5d9074)
2012-10-27 16:12:57 +00:00
zzz
eafca84717 0.9.3 2012-10-27 13:03:14 +00:00
zzz
0e2fd0c6f5 tweak 2012-10-27 12:47:07 +00:00
zzz
0ccf65fcf8 banlist 2012-10-26 16:24:31 +00:00
zzz
af06fded73 - Add password enabled property
- Bypass nonce checking if passwords enabled
  - Add message about cookies if nonce fails
  - Minor susidns cleanup
2012-10-26 13:08:23 +00:00
zzz
0bfe8ff41d * BuildHandler: Fix "too slow" rejections due to internal clock skew 2012-10-25 18:58:12 +00:00
str4d
804f0294bb Bumped router to -21 for previous commit 2012-10-25 02:51:18 +00:00
str4d
7a4430856d Tweaked default value of lastLine in susimail to make a no-response error clearer to users 2012-10-25 02:49:13 +00:00
str4d
6bd40e253a Bumped router to -20 for previous commit 2012-10-24 19:55:35 +00:00
str4d
c2d178efc3 Fixed a very stupid bug >_< 2012-10-24 19:51:54 +00:00
zzz
97da508df5 * I2PSnark:
- Fix (again) partial piece avoidance for seeds
   - Fix several partial piece (temp file) leaks,
     some uncovered by previous rarest-first fixes, some in end game
   - Don't lose all DHT peers if we stop quickly (backport from update branch)
   - Explore a kbucket if it's less than 3/4 full (backport from update branch)
2012-10-24 17:38:20 +00:00
str4d
211128f128 i2ptunnel: Truncate long client destinations (ticket #581) 2012-10-24 02:30:19 +00:00
zzz
2f69d16828 - Thread magnet start if not connected
- Don't lose all DHT peers if we stop quickly
- Explore a kbucket if it's less than 3/4 full
- Change release torrent file names
2012-10-23 19:34:35 +00:00
zzz
bb2363f68a - Fix DummyHandler
- Notes on news.xml enhancements
- Fix handling existing torrent
- Add dn to magnet link generation
- Fix progress info
2012-10-23 14:09:14 +00:00
meeh
fc461931bd Adding a new reseed host. 2012-10-23 14:08:12 +00:00
zzz
724f4f9b37 - Several plugin install fixes
- Remove unused UpdateTypes
- Only try applicable updaters when updating
- Javadoc fixes
2012-10-23 02:34:24 +00:00
zzz
6f790d99c9 exit 1 on failure 2012-10-22 22:56:40 +00:00
zzz
efb986ffd9 - Handle case where we already have torrent
- New Storage.main() for use in the release process
- Make torrent files in release process
- Stop tunnel after fatal if no snarks are running
2012-10-22 22:55:36 +00:00
zzz
bd9ad9982b - Fix spacing in summary bar
- Add start() in UpdateTask so things happen in the right order
- Add toString() in UpdateTask for better debugging
- Fix getID() for plugin UpdateTasks
2012-10-22 20:25:01 +00:00
meeh
e5a8a6aba4 merge of '7ca37d4f5e443834de23ebd2cf306b6fe3aeca87'
and 'f9d82ac84936c56dc92691842757e8cc354511e2'
2012-10-22 20:24:53 +00:00
meeh
da835fbd6b h2ik don't have static ip anymore. 2012-10-22 19:52:21 +00:00
zzz
1538e6ec4e - Fix VersionComparator (thx zab)
- Add debug output
2012-10-22 17:13:23 +00:00
zzz
95e0c37222 - Add fail timers
- Add progress indication
- Listener cleanup
2012-10-22 14:51:41 +00:00
zzz
95870df45b * Watchdog: Don't dump threads too often (ticket #519) 2012-10-21 17:21:49 +00:00
zzz
8b2889e317 - Only fail after all URLs are tried
- Move registration from servlet to manager and delay
- Fix plugin updates
- More logging
2012-10-21 17:14:54 +00:00
zzz
0fc452b683 - Improved parsing of news file
- Add magnet links to news file
2012-10-21 14:59:52 +00:00
zzz
6e19854e4c - NPE fix on signed udpates
- More work on snark updater
- Clean up imports
2012-10-21 13:34:23 +00:00
zzz
6331cb2374 stub of a torrent updater 2012-10-21 03:13:31 +00:00
zzz
983537b0fd refactor CompleteListener out of Snark.java 2012-10-21 02:34:46 +00:00
zzz
58fd2dddf8 refactor magnet parsing out of servlet 2012-10-21 02:08:34 +00:00
zzz
49b2fbd2b0 tweak 2012-10-20 22:52:11 +00:00
zzz
68814e31e7 * Console:
- Store form handler nonces in the servlet session instead of system properties,
    to prevent cross-session interference
2012-10-20 21:28:17 +00:00
zzz
429739837b * Console:
- Consolidate all the jsp formhandler boilerplate in the new
    formhandler.jsi, in preparation for further improvements
2012-10-20 20:52:45 +00:00
zzz
fef1440865 * Transport:
- Add a simple network monitor
  - Add new reachability state for network disconnected
  - Prevent any tunnel building when disconnected (ticket #519)
  - Don't unleash watchdog when disconnected
2012-10-20 17:28:00 +00:00
zzz
afd29715fa * Addresses:
- Add methods for connectivity detection
  - Remove Hamachi restriction
2012-10-20 15:30:12 +00:00
zzz
e329742c8d * Transport: Back out CoDel for SSU PeerState and NTCP 2012-10-20 11:37:31 +00:00
zzz
5695d0e94a build fix 2012-10-20 03:38:54 +00:00
zzz
5a964dacbb * UDP: Fix peer test NPE (ticket # 748) 2012-10-19 22:03:41 +00:00
zzz
fea3bb63c1 - Save available unsigned version across restarts
- Fix status display after downloaded
- Don't display update buttons unless HTTP proxy is up
- Pass the manager down thru the constructors
2012-10-19 20:26:08 +00:00
kytv
580c940d42 More pt trans updates from tx 2012-10-19 07:49:36 +00:00
kytv
7ea8cd4a09 Geoip update 2012-10-18 22:37:50 +00:00
zzz
4f936f958d add the other getProperty(); more tweaks 2012-10-18 21:07:36 +00:00
kytv
a6ca962fcb Portuguese and Spanish updates from Transifex 2012-10-18 15:19:13 +00:00
zzz
0b4401e64b - Lots of fixes for notifying when updates and checks are complete
- Fixes for NewsHelper stored timestamps
- Add getProperty(String, long) to context for sanity
- New methods and types
- Logging improvements
- Add failsafe TaskCleaner
2012-10-18 14:28:14 +00:00
zzz
2b50c5aaf4 comment out test code 2012-10-18 14:26:30 +00:00
zzz
da4ea77c2a more fixes 2012-10-18 02:20:39 +00:00
zzz
af4786ce0e fixes 2012-10-18 01:29:14 +00:00
zzz
f9b8f0528d - Straighten out some confusion on versions, RFC 822 dates,
etc. on news and unsigned updates. Stored versions are always
  Long.toString(modtime). Only convert to RFC 822 for eepget or display.
2012-10-17 23:45:44 +00:00
zzz
b9d717b9f9 - Split up Updater and Checker interfaces
- Update router after check
2012-10-17 22:24:15 +00:00
zzz
cbc9165afd - Add a jetty starter that can be stopped later
- Include jetty-i2p.jar in the updaters
2012-10-17 17:37:45 +00:00
zzz
a9e18620b9 - Convert HTTP and CONNECT proxies to MD5 authentication
- Allow multiple users
  - Migrate passwords on first save
2012-10-16 19:17:06 +00:00
zzz
613dd77d2c only display tracker error if no peers 2012-10-15 21:30:46 +00:00
zzz
9b6d5daeef more work on proxy digest auth 2012-10-15 21:04:49 +00:00
kytv
b816ecc7e3 Italian and Swedish updates from Transifex 2012-10-15 18:05:38 +00:00
zzz
d01aae7860 HTTP Proxy:
- Move error page methods to base
 - Preliminary code for digest auth
2012-10-15 15:37:13 +00:00
zzz
50cb427377 split out md5Sum for use in i2ptunnel 2012-10-15 13:57:09 +00:00
zzz
977cdee046 - Move MD5 functions to core util where i2ptunnel can use them 2012-10-15 12:28:45 +00:00
zzz
4db4010abf propagate from branch 'i2p.i2p' (head 2da3b585b42d058e25909bc303d72277ae2463b5)
to branch 'i2p.i2p.zzz.update' (head ebbad994215dc2822e9a1776399864ed77a0e5a0)
2012-10-14 22:42:00 +00:00
zzz
ba37839adf fixes while rechecking storage 2012-10-14 20:05:04 +00:00
zzz
c9196fda03 compile fixes after prop 2012-10-14 20:03:56 +00:00
zzz
b03b4745db propagate from branch 'i2p.i2p' (head 2da3b585b42d058e25909bc303d72277ae2463b5)
to branch 'i2p.i2p.zzz.test' (head 2785f3832a7d1b8adb2f106d049949beb9b88838)
2012-10-14 19:50:51 +00:00
zzz
8df2a2d00a * i2psnark: Fix request tracking bug preventing piece requests 2012-10-14 16:38:36 +00:00
zzz
184220f4c5 minor optimization 2012-10-14 13:54:38 +00:00
zzz
5d6d27907d * Console: Use non-nio connector for Java 5 and JamVM/gij
(tickets #715 and #743)
 * SystemVersion: Centralize more methods here
2012-10-14 13:54:08 +00:00
zzz
5e5dc35a1e moved i2cp password to PasswordManager 2012-10-13 22:42:26 +00:00
zzz
24b7b6fabd - Don't migrate any plaintext passwords to obfuscated, it's too messy 2012-10-13 21:42:52 +00:00
zzz
c5ab6b9993 * Passwords:
- Add remove method
    - Add console password form to configui.jsp
    - Consolidate multiple setSettings()/getJettyString() in FormHandler
    - Some form message tweaks
2012-10-13 21:20:16 +00:00
zzz
05740f7903 - Fix MD5 passwords after testing
- Remove unused password fallback in FormHandler
2012-10-13 15:41:57 +00:00
zzz
fc7f995bd2 propagate from branch 'i2p.i2p' (head 2ab4ae45aa60b379e85fca378522966c090a1a27)
to branch 'i2p.i2p.zzz.test' (head 220477e37d4df782b9a8bb30d12669d146dc6226)
2012-10-13 14:23:29 +00:00
zzz
d99a39e5d5 convert to ClientApp interface. Untested. 2012-10-13 13:54:30 +00:00
zzz
0b897fdc98 * RouterConsoleRunner:
- Prep for ClientApp interface by storing context in a field,
      shuffle around what's static and what's not
      (ticket #347)
    - Remove ports from port mapper on shutdown, other changes to
      track actual ports better
      (ticket #731)
    - Hook in password manager using MD5, untested.
      (ticket #731)
2012-10-13 13:06:22 +00:00
zzz
a475a912e6 * New password manager for storing passwords in router.config
in consitent ways, including salting and hashing if possible.
    Not hooked in to console yet, lightly tested.
    (ticket #731)
2012-10-13 12:56:43 +00:00
zzz
8f17b73091 changes due to LoadClientAppsJob changes for ClientApp interface 2012-10-13 12:51:24 +00:00
kytv
cb56b76ef9 i2prouter: check /proc/1/comm for systemd (thanks k0e) 2012-10-13 12:45:25 +00:00
zzz
d198ae9ef1 * New interface for clients started via clients.config, and a new
manager to track the lifecycle and start/stop clients on demand.
    Not hooked in to console yet, untested.
    (ticket #347)
2012-10-13 12:45:08 +00:00
kytv
eff238e85c i2prouter: In Slackware, check for existence of /etc/rc.d/rc.i2p when installing as a daemon 2012-10-12 17:26:03 +00:00
kytv
a436e60fb8 Italian translation updates / updated EN po files 2012-10-12 00:52:09 +00:00
kytv
2c570f8d4e remove internel I2P link
Let's not direct people to see how to configure their browser at
http://www.i2p2.i2p/htproxyports when you need to have your proxy configured to go there!
2012-10-11 22:48:06 +00:00
kytv
6f23bdd331 remove another link to forum.i2p2.de 2012-10-11 22:43:51 +00:00
kytv
b797f9e26d remove link to forum.i2p2.de 2012-10-11 22:42:03 +00:00
kytv
2b13973eca debian: refresh patches 2012-10-10 23:32:27 +00:00
kytv
9331b229fe addressing a few concerns from #681 2012-10-10 23:32:04 +00:00
kytv
ccd0795a4e turn off executable bit 2012-10-10 23:31:07 +00:00
kytv
1f98493dbd i2prouter: add initscript support to Slackware 2012-10-10 22:44:42 +00:00
kytv
f20d906b67 i2prouter: Add systemd support for Arch Linux and SuSE Linux. 2012-10-10 21:33:05 +00:00
zzz
65757dee1c * ShellCommand: Fix launching all browsers at startup (ticket #453) 2012-10-10 19:12:30 +00:00
zzz
b259a3ac3d * stats.jsp: Sort groups by translated name 2012-10-10 19:11:18 +00:00
zzz
ca1f816ad9 remove colombo 2012-10-10 15:06:51 +00:00
zzz
6f509967bf Making FIFOBandwithLimiter.Request unidirectional, static,
remove logging, other cleanups (ticket #719)
2012-10-09 14:15:04 +00:00
zzz
56574c41be propagate from branch 'i2p.i2p' (head cbca70618d2083a5fcdead2390e9d30060080e74)
to branch 'i2p.i2p.zzz.test' (head 1affab2e83613f326d269370de6e5aed40ecae52)
2012-10-09 13:36:32 +00:00
zzz
3cdfc2d33a Split up NTCPConnection's single _bwRequests Set into inbound and outbound,
in prep for making FIFOBandwithLimiter.Request unidirectional
and support priorities (ticket #719)
2012-10-09 13:36:14 +00:00
zzz
1b154551a2 EventLog: add more events 2012-10-09 10:35:47 +00:00
zzz
c419016a12 * SSU:
- Add peer test throttling
   - Peer test packet count fixes
   - Adjust peer test timeouts and add backoff
   - Reject relays and peer tests from same /16
   - More peer test cleanup and log tweaks
 * Transports:
   - Enforce minimum peer port
   - Warn on low router ports
2012-10-09 10:20:45 +00:00
zzz
f10478ceef comment out test 2012-10-09 10:16:05 +00:00
zzz
d477773054 * NetDB: Increase floodfills again 2012-10-09 10:15:44 +00:00
zzz
8ed280ebf4 * RouterInfo: Exit 1 on error in main() 2012-10-09 10:14:56 +00:00
zzz
762e96b8a6 2 more for cache 2012-10-09 10:13:59 +00:00
zzz
23c77fbe4b * Console, i2ptunnel: Warn on low ports 2012-10-09 10:13:10 +00:00
zzz
e99dd72cb6 * SSU:
- Fix relay request handling bug from -10
   - Fix peer test reply handling bug from -10
   - Fix NPE from -6
2012-10-08 09:32:04 +00:00
zzz
b095b7e769 * i2ptunnel:
- Set default read timeout in standard server
   - Reduce header timeout, enforce total header timeout
     in IRC and HTTP servers (ticket #723)
 * Streaming: Don't ignore option or force connect timeout to 5 minutes
 * Streaming javadocs
 * SocketTimeout cleanup
2012-10-07 20:57:35 +00:00
zzz
6b97e1bfaf * Logs:
- Flush buffers in logs.jsp
   - Add dup message to buffers, was in file only
2012-10-07 20:50:26 +00:00
zzz
3ceb83d40e * I2PAppContext: Improved synching in constructor 2012-10-07 20:48:25 +00:00
zzz
d80340f0ae * UPnP: Workaround NPE (ticket #728)
root cause TBD
2012-10-07 20:47:22 +00:00
zzz
3acc2fb160 - Much improved peer test defenses
- Minor improvements to relay defenses
2012-10-06 22:47:17 +00:00
zzz
034db1a282 Validate port/IP in received peer tests 2012-10-06 14:58:42 +00:00
zzz
b07b9bf0b9 * SSU:
- Throttle outbound destroys on shutdown
   - Limit outbound introduction offers
2012-10-06 13:44:57 +00:00
zzz
97460e7d99 * configlogging.jsp: Fix IAE
* error500.jsp: Fix whitespace
2012-10-06 13:42:48 +00:00
zzz
ddc750469c * i2psnark:
- Add allocating and checking indications
   - Add bandwidth message at startup
   - More checks at torrent creation
2012-10-06 13:41:50 +00:00
zzz
0448537509 make inbound and exploratory settings final 2012-10-05 13:38:27 +00:00
zzz
583463ab42 * configservice.jsp: Add GC button 2012-10-05 13:09:34 +00:00
zzz
b20e298f6e * SSU:
- More synchronization fixes
   - Reduce chance of dup acks in a single message
   - Reduce max unsent acks to 50
   - Use last ack time in ping decision too
   - Reduce ack delay
2012-10-05 13:08:05 +00:00
zzz
090d59fcb7 * DataHelper: Sanity checks in storeProps(), use
storeProps() for router config again
2012-10-05 13:00:52 +00:00
zzz
1d174d6797 * TunnelPoolManager: Fix early NPE (ticket #724) 2012-10-05 12:59:30 +00:00
zzz
15a47b5612 import 2012-10-03 19:17:55 +00:00
zzz
4d1ea6e4cd * SSU:
- Increase max outbound establishments based on bandwidth
   - Synchronization fix for Java 5
   - Use multiple buffer sizes in OutboundMessageState to
     reduce memory usage
   - Adjust skew calculation, synchronize too
   - Ping loop improvements
2012-10-03 19:05:56 +00:00
zzz
13ef00cb2e add hasWrapper() 2012-10-03 17:41:33 +00:00
zzz
d2c1641569 * NTCP: Reduce conLock contention 2012-10-03 17:40:59 +00:00
zzz
a1873e74e5 cleanup 2012-10-03 17:40:31 +00:00
kytv
8be86fe80c debian: rework oom patch 2012-10-02 19:26:04 +00:00
zzz
4dc90ef5da * SSU:
- Fix memory leak in _peersByRemoteHost map caused by not
     removing peers that change IP or port
   - Send keepalives if firewalled
   - Handle peers that change ports on an established session
   - Synchronize adds and drops
   - Don't use peers with high RTTs in clock skew calculation
   - Reduce initial RTT/RTO
2012-10-02 18:36:06 +00:00
zzz
e130264254 * NTCP: Only set keepalive if firewalled 2012-10-02 12:41:31 +00:00
zzz
93039a6813 * OOMListener: Dump threads on OOM 2012-10-02 12:40:00 +00:00
zzz
07b3c8a7b4 * PRNG, LogWriter: Use I2PThread to catch OOM 2012-10-02 12:38:05 +00:00
zzz
83fe635438 * i2ptunnel: Fix log message 2012-10-02 12:37:16 +00:00
zzz
3ee96fb663 * i2psnark: Fix delete download message 2012-10-02 12:36:34 +00:00
zzz
6684ba1b1d * I2CP: Delay after sending disconnect message to
help it get through
2012-10-02 12:35:45 +00:00
zzz
466778875d * SimpleByteCache: Fix ABQ/LBQ selection 2012-10-02 12:34:29 +00:00
zzz
a71e8fae00 * i2psnark:
- Fix bugs in rarest-first tracking
   - Fix requesting of partial piece when there are multiple seeds
   - Synch fix in BitField
2012-09-28 19:25:31 +00:00
zzz
f58bf3028a javadoc 2012-09-28 19:08:00 +00:00
zzz
595556c39f * SessionKeyManager: Store original tagset size for debugging 2012-09-28 19:06:39 +00:00
zzz
eeaa4fbbb4 * peers.jsp: Remove SSU "Dev" column 2012-09-28 18:48:58 +00:00
zzz
49b11e1f84 * Streaming: Don't send RST on globally-blackisted conns 2012-09-28 18:48:16 +00:00
zzz
e3133d88d7 javadoc 2012-09-28 18:42:17 +00:00
zzz
1a50b6243d volatile 2012-09-28 18:41:19 +00:00
zzz
076558d4f5 * i2ptunnel: Fix wrong server IP in log message 2012-09-28 18:40:49 +00:00
zzz
fb5d0cd760 Boolean.valueOf(x).booleanValue() -> Boolean.parseBoolean(x) 2012-09-28 17:50:41 +00:00
zzz
7c8ba61f03 fix date 2012-09-26 20:03:10 +00:00
zzz
20e463e41b * Streaming:
- Implement changing connection limits on a running session
   - Implement global blacklist
2012-09-26 20:02:36 +00:00
zzz
5d3984e353 * Addresses: Reject numeric IPs of the form n, n.n, and n.n.n
* Console, i2ptunnel: More validation of address and port in forms
2012-09-26 20:00:59 +00:00
zzz
941aea80bb javadoc 2012-09-26 19:58:19 +00:00
zzz
0533aa7f6f * RFC822Date: Synchronization fix 2012-09-26 19:58:08 +00:00
zzz
568e2d5063 tweak to port field CSS 2012-09-26 19:57:37 +00:00
zzz
86c7aa8b8a * i2psnark: Enable DHT by default 2012-09-26 19:57:01 +00:00
zzz
f61e7a193f * ConvertToHash:
- Add support for b64hash.i2p (output in jetty logs)
   - Cleanup and use cache
2012-09-26 19:56:33 +00:00
str4d
567dae8ced merge of '6ccace0742effd1eaadcc151f428825fa3215e12'
and 'dc06981e777b7e1c191937d6d8190b26a8f6bbc7'
2012-09-25 22:26:47 +00:00
str4d
02f483a873 Modified susimail footer so <hr> is hidden as well 2012-09-25 21:57:22 +00:00
zzz
7051e1c5f6 * UPnP: Cleanup & final 2012-09-25 19:30:49 +00:00
zzz
87295b4bfd * URLLauncher: Add xdg-open (ticket #617); minor refactor 2012-09-25 19:25:01 +00:00
zzz
23ca6b4fac * SimpleByteCache: Concurrent fix 2012-09-25 19:24:11 +00:00
zzz
9e3559625c * OutboundEstablishState: Cleanup (ticket #671) 2012-09-25 19:22:36 +00:00
zzz
351d582c8f * Jetty: Add non-NIO selector option (ticket #715) 2012-09-25 19:21:28 +00:00
zzz
5b1ea6187f * EventLog: Fix IAE on portable 2012-09-25 19:20:15 +00:00
zzz
211782fae4 * Context: Make files final 2012-09-25 19:19:27 +00:00
zzz
20279d1597 propagate from branch 'i2p.i2p' (head 52d5a19210a344e0de43f6fe4d898d34f6c41829)
to branch 'i2p.i2p.zzz.update' (head d88c6abf9b4988ba892e435594cd74917ab9ab7f)
2012-09-25 15:04:49 +00:00
str4d
44466aa769 Modified susidns footer so <hr> is hidden as well 2012-09-24 22:17:05 +00:00
str4d
d27d014eb0 Show susi footer on susimail and susidns when displayed standalone
Footer hidden when embedded because of margin issues, and out-of-place-ness.
Have confirmed that susi's opinion when the themes were initially updated was
"do what you want", so no legal problem.
2012-09-22 23:47:57 +00:00
zzz
e884ca54ef -1 2012-09-21 17:54:46 +00:00
zzz
336420cf50 propagate from branch 'i2p.i2p.zzz.test' (head 5dadb7923797a3e6d9ead4d4b17ab7e0e0201b2b)
to branch 'i2p.i2p' (head 703251aaf19111efe6fac5a4ae49f00a1aac1e9e)
2012-09-21 17:50:59 +00:00
zzz
0eedc3aa19 intern strings 2012-09-19 20:47:50 +00:00
zzz
f232775161 CoDel for build handler 2012-09-19 19:00:06 +00:00
zzz
bd57463d42 fix NTCP backlogged indication 2012-09-18 12:37:30 +00:00
zzz
2c4910e9e7 * ByteCache, ByteArray:
- Cleanups and javadocs
    - Prevent release of a wrong-sized array
2012-09-17 21:57:16 +00:00
zzz
2b14d32bea use ByteCache for chunks in/out 2012-09-17 21:32:05 +00:00
zzz
259c28f8c1 startup/shutdown synchronization in several places 2012-09-16 15:47:36 +00:00
zzz
b6a5360390 log/stat tweaks 2012-09-16 15:46:36 +00:00
zzz
0b7b947786 increase flush interval 2012-09-16 15:43:36 +00:00
zzz
147e257cee comment out main() 2012-09-16 15:43:06 +00:00
zzz
68ccb3a944 cleanup 2012-09-14 13:53:36 +00:00
zzz
b9aceb895d * SSU:
- Increase initial and max RTO
    - Don't count ack-only packets in bandwidth allocation
    - Unused method cleanup
2012-09-12 21:55:15 +00:00
zzz
8633ef9513 * Streaming: Don't send a RST to an hour/day limited peer,
or blacklisted, or non-whitelisted, to not waste outbound bandwidth
2012-09-12 21:52:12 +00:00
zzz
4666454482 improve dup log message 2012-09-11 19:50:59 +00:00
zzz
db42d9ec37 * FortunaRandomSource:
- Fix bug that wasted entropy in nextInt()
    - Improved synchronization
2012-09-11 19:40:20 +00:00
zzz
d7b48a2256 change what we call imminent so we dont display ms 2012-09-10 22:40:21 +00:00
zzz
50ec279917 use partial match for dups; add config for dups 2012-09-10 22:38:18 +00:00
zzz
e8a8f3c210 * TunnelGateway: Implement pushback from a backlogged transport
queue to the pre-fragmentation queue
2012-09-10 21:30:54 +00:00
zzz
e0fc642fc3 reduce _jobLock contention 2012-09-10 17:27:18 +00:00
zzz
835ed6d9bb boost priority of shutdown thread 2012-09-10 17:25:00 +00:00
zzz
3781928693 logging cleanups 2012-09-10 17:22:51 +00:00
zzz
2f98d05e7c * Clock: Synchronization, log large shifts to event log 2012-09-09 15:45:29 +00:00
zzz
74e753934c * SystemVersion: New util, to consolidate duplicate code,
and determine Java version on Android
2012-09-09 15:40:14 +00:00
zzz
9bc54f27cf * ClientManager:
- Concurrent client map for faster lookup
    - Add by-hash client map for faster lookup by hash
    - More cleanups
2012-09-08 21:56:05 +00:00
zzz
d9e6c06b22 * I2CP: Buffer output streams
* ClientConnectionRunner: More cleanups and edge cases
2012-09-08 20:45:11 +00:00
zzz
e02d82981a - Run HandleJob inline for speed
- Remove payload from message map if availability announce fails
- Cleanups
2012-09-08 15:10:27 +00:00
zzz
98da06cd83 limit queue size, make nonblocking 2012-09-08 14:25:04 +00:00
zzz
0d62266008 * ClientConnectionRunner: Run MessageReceivedJob inline for speed 2012-09-08 14:04:01 +00:00
zzz
1ae0c2e312 add -test 2012-09-08 13:15:58 +00:00
zzz
61629080b2 propagate from branch 'i2p.i2p' (head 86f3e7e668b7ec9f2ddf75be7586719944bbc37f)
to branch 'i2p.i2p.zzz.test' (head da9536c250bc4c0b7523ed748574de1cc97f3028)
2012-09-08 12:57:09 +00:00
zzz
4cf104720c * PumpedTunnelGateway:
- Move OBGW queue to CoDelPriority
    - Move IBGW queue to CoDel
    - Reduce max pumped per cycle for IBGW
2012-09-08 12:47:17 +00:00
zzz
2c866e205b * NTCP: Move NTCPConnection outbound queue to CoDelPriority
* SSU:
    - Separate PeerState outbound message list into a queue for unsent messages
      and a list for sent messages awaiting ack
    - Implement PeerState outbound queue as CoDelPriority
    - Implement backlogged indication like in NTCP
2012-09-08 12:40:27 +00:00
zzz
ca91ad3188 * SSU: Move MessageReceiver queue to CoDel 2012-09-08 12:34:34 +00:00
zzz
33de6beab3 * SSU: Move UDPSender and UDPReceiver queues to CoDel 2012-09-08 12:29:55 +00:00
zzz
871f046755 adjust target and interval, and backlogged indication 2012-09-08 12:23:43 +00:00
zzz
aef021dcd1 * I2CP: Limit router/client queue sizes and queue wait times 2012-09-07 22:49:24 +00:00
zzz
489f43529c booleanValue() -> parseBoolean() 2012-09-07 20:13:49 +00:00
zzz
78203aac9a * i2psnark:
- Implement blacklist for unreachable DHT peers
    - Reduce threshold for unreachable
    - Log tweaks
2012-09-07 20:10:01 +00:00
zzz
3c95f0b66b * LogWriter: Duplicate log message removal 2012-09-07 18:53:24 +00:00
zzz
3347788712 add isBacklogged() 2012-09-06 19:53:01 +00:00
zzz
0c5b4c05c6 minor cleanups 2012-09-06 19:25:31 +00:00
zzz
b8949eafe2 Non-codel version of priority blocking queue, so we can
implement priority queues without necessarily committing to codel.
2012-09-05 15:50:11 +00:00
zzz
9286d6a7b8 * IP Lookup:
- Add caching in RouterAddress with secondary caching
      in Addresses; use caches to speed up transport bids,
      blocklist checks, geoip lookups, and profile organizer checks
      (ticket #707)
    - Limit IP cache size in TransportImpl
    - Clear caches at shutdown
  * RouterAddress: Remove unused expiration field to save space
2012-09-04 20:33:04 +00:00
zzz
2cddf1405f log tweaks 2012-09-04 00:27:04 +00:00
zzz
8575437626 * LHMCache: New util, replacing several private versions 2012-09-03 15:33:12 +00:00
zzz
c965a3dca0 add drainAllTo() 2012-09-02 14:41:21 +00:00
zzz
c48aca8d5c ByteCache: Move all 16/32 byte users to SimpleByteCache;
increase SimpleByteCache default size.
2012-09-02 12:31:08 +00:00
zzz
4360284355 stat and log tweaks 2012-09-02 00:45:58 +00:00
zzz
f44eeaf7dd TunnelGateway: Refactor TunnelGateway.Pending to its own file PendingGatewayMesasge 2012-09-01 21:39:14 +00:00
zzz
a0418bec59 OutNetMessage:
- Centralize priority definitions
  - Raise netdb store and reply priority
GarlicMessage:
  - Add notes about GarlicMessageHandler and HandleGarlicMessageJob
    being unused in practice
2012-09-01 20:47:22 +00:00
zzz
5eff26e40e add minimum priority check 2012-09-01 20:17:37 +00:00
zzz
4e78517651 TunnelGateway:
- Limit queue sizes
  - Add stat for overflow
  - Remove some stats
  - Change pumper to LinkedHashSet for efficiency
    (like NTCP Reader/Writer)
  - Limit messages pumped per cycle to increase
    round-robin fairness
  - Comment out some unused code
  - Javadoc
2012-09-01 17:20:52 +00:00
zzz
10d9eb70c8 CoDel:
- Add logging of drops
  - Set drop stat to delay of dropped item
  - Add no-drop priority
2012-09-01 16:30:12 +00:00
zzz
8bfbe855a1 one last SimpleTimer 2012-09-01 13:40:38 +00:00
zzz
3fbf60ee21 Codel:
- Override poll() and drainTo()
  - Tweak stats
  - Add PriorityBlockingQueue version
2012-09-01 13:21:25 +00:00
zzz
6bfd916fef SimpleTimer (ticket #653):
- Move all remaining uses to SimpleTimer2
    - Deprecate
2012-09-01 13:14:15 +00:00
zzz
94f370e76c propagate from branch 'i2p.i2p' (head 871765966dc474b763ff0d5c017bed7535981c1e)
to branch 'i2p.i2p.zzz.test' (head 096242c22aa550274cb383a6a0c984cef07ae08c)
2012-08-31 14:41:18 +00:00
zzz
0689b03603 - Prevent crashes at update caused by event log starting timestamper thread 2012-08-30 15:29:35 +00:00
zzz
ee8cd29da9 New AQM blocking queue using CoDel reference implementation - untested. 2012-08-30 14:20:37 +00:00
zzz
c4a3159b33 Replace ident log with new, general-purpose event log.
Use for stops, starts, and updates, and others.
Mark all restarts on graphs using the event log.
2012-08-30 14:06:06 +00:00
str4d
b464ef0ac3 propagate from branch 'i2p.i2p.unittests' (head 58a62605ce8542f7e5d5daf0c2e171ed0c7e1a74)
to branch 'i2p.i2p.zzz.update' (head 269547972f0e02fe545296823602995465bb0691)
2012-08-08 00:15:55 +00:00
str4d
7f09206a47 Fixed jarScalaTest targets to actually package all classes 2012-08-08 00:07:17 +00:00
str4d
65573eafac Use ScalaTest jars in routerconsole tests 2012-08-07 23:12:37 +00:00
str4d
aab2c0601d propagate from branch 'i2p.i2p.unittests' (head fb681c6fa25bcf9f7287a661b3ce626fd5a280bb)
to branch 'i2p.i2p.zzz.update' (head f3c8cb8ad1d68cc6a66d544f1e287eead786c5ce)
2012-08-07 12:42:48 +00:00
str4d
5355e5bbfd Added targets to build i2p.jar and router.jar with ScalaTest classes included 2012-08-07 11:58:11 +00:00
str4d
07e18c07ac Added ScalaTest support to routerconsole build.xml
To run (once tests exist) execute something like

ant -Dclasspath=/usr/share/java/mockito-core.jar
    -Dscalatest.libs=./lib
    -Dwith.cobertura=/usr/share/java/cobertura.jar
    fulltest
2012-08-05 22:20:19 +00:00
zzz
94d51bd56f log tweaks 2012-08-03 19:58:38 +00:00
zzz
72ed1bc1ac fixups after prop 2012-08-03 18:56:53 +00:00
zzz
4a1b83961d propagate from branch 'i2p.i2p' (head d2198c4bc21a9d06194cdb2dce24945ebc9d1542)
to branch 'i2p.i2p.zzz.update' (head 88ac67dc4e166b7e9dec0d3224e58bec4894440d)
2012-08-03 18:30:39 +00:00
zzz
e62b76d2cc Big refactor of the router console update subsystem, in preparation for
implementing out-of-console updaters like i2psnark.

- Add new update interfaces in net.i2p.update
- All update implementations moved to routerconsole update/
- Implement an UpdateManager that registers with the RouterContext
- UpdateManager handles multiple types of things to update
  (router, plugins, news, ...) and methods of updating (HTTP, ...)
- UpdateManager maintains list of installed, downloaded, and available versions of everything
- Define Updaters that can check for a new version and/or download an item
- Individual Updaters register with the UpdateManager obtained from
  I2PAppContext, identifying the type of update item and
  update method they can handle.
- Updaters need only core libs, no router.jar or routerconsole access required.
- All checks and updates are initiated via the UpdateManager.
- All status on checks and updates in-progress or completed are
  obtained from the UpdateManager. No more use of System properties
  to broadcast update state.
- All update and checker tasks are intantiated on demand and threaded;
  no more static references left over.
- Split out the Runners and Checkers from the Handlers and make the inheritance more sane.
- No more permanent NewsFetcher thread; run on the SimpleScheduler queue
  and thread a checker task only to fetch the news.
- No more static NewsFetcher instance in routerconsole.
  All helper methods that are still required are moved to NewsHelper.

The UpdateManager implements the policy for when to check and download.
All requests go through the UpdateManager.

For each update type, there's several parts:
    - The xxxUpdateHandler implements the Updater
    - The xxxUpdateChecker implements the UpdateTask for checking
    - The xxxUpdateRunner implements the UpdateTask for downloading

New and moved classes:

web/				update/
----				-------
new				ConsoleUpdateManager.java

new				PluginUpdateChecker.java from PluginUpdateChecker
PluginUpdateChecker 		-> PluginUpdateHandler.java
PluginUpdateHandler.java	-> PluginUpdateRunner

new				UnsignedUpdateHandler.java
UnsignedUpdateHandler		->  UnsignedUpdateRunner.java
new				UnsignedUpdateChecker from NewsFetcher

UpdateHandler.java remains
new				UpdateHandler.java
new				UpdateRunner.java from UpdateHandler

move				NewsHandler from NewsFetcher
new				NewsFetcher
new				NewsTimerTask

new				DummyHandler


Initial checkin. Unfinished, untested, unpolished.
2012-06-18 22:09:45 +00:00
zzz
9d91b90d3c propagate from branch 'i2p.i2p' (head d32b82100cf6076e8f3de30b6a0edfbb034caac7)
to branch 'i2p.i2p.zzz.pcap' (head 551957edb05526df88ff3a2b3c717faed4aac906)
2009-12-27 15:07:45 +00:00
zzz
9203663abf propagate from branch 'i2p.i2p' (head 3f19ceea830345f8c34cbccfef3c759d48cd2f7e)
to branch 'i2p.i2p.zzz.pcap' (head fe70e551db5af3ebac9564b4868a28a1ebab7227)
2009-11-23 13:39:27 +00:00
zzz
d078ed396f move init, add config 2009-11-06 19:16:23 +00:00
zzz
7c36c0c8e7 add TCP options block 2009-11-06 16:39:05 +00:00
zzz
404754bc90 streaming lib packet capture first cut 2009-11-06 12:47:21 +00:00
946 changed files with 137023 additions and 89992 deletions

View File

@@ -2,6 +2,7 @@
# Use mtn add --no-respect-ignore foo.jar to ignore this ignore list
_jsp\.java$
\.bz2$
\.tar$
\.class$
\.diff$
\.exe$
@@ -15,6 +16,7 @@ _jsp\.java$
\.su2$
\.tar$
\.war$
.\deb$
\.zip$
^\.
^build
@@ -23,4 +25,7 @@ _jsp\.java$
/build
/classes/
^debian/copyright
^debian/changelog
override.properties
sloccount.sc
^reports/

View File

@@ -9,7 +9,10 @@ trans.es = apps/i2ptunnel/locale/messages_es.po
trans.fr = apps/i2ptunnel/locale/messages_fr.po
trans.hu = apps/i2ptunnel/locale/messages_hu.po
trans.it = apps/i2ptunnel/locale/messages_it.po
trans.nb = apps/i2ptunnel/locale/messages_nb.po
trans.nl = apps/i2ptunnel/locale/messages_nl.po
trans.pl = apps/i2ptunnel/locale/messages_pl.po
trans.pt = apps/i2ptunnel/locale/messages_pt.po
trans.ru = apps/i2ptunnel/locale/messages_ru.po
trans.sv_SE = apps/i2ptunnel/locale/messages_sv.po
trans.uk_UA = apps/i2ptunnel/locale/messages_uk.po
@@ -25,13 +28,15 @@ trans.da = apps/routerconsole/locale/messages_da.po
trans.de = apps/routerconsole/locale/messages_de.po
trans.el = apps/routerconsole/locale/messages_el.po
trans.es = apps/routerconsole/locale/messages_es.po
trans.et_EE = apps/routerconsole/locale/messages_ee.po
trans.et_EE = apps/routerconsole/locale/messages_et.po
trans.fi = apps/routerconsole/locale/messages_fi.po
trans.fr = apps/routerconsole/locale/messages_fr.po
trans.hu = apps/routerconsole/locale/messages_hu.po
trans.it = apps/routerconsole/locale/messages_it.po
trans.nb = apps/routerconsole/locale/messages_nb.po
trans.nl = apps/routerconsole/locale/messages_nl.po
trans.pl = apps/routerconsole/locale/messages_pl.po
trans.pt = apps/routerconsole/locale/messages_pt.po
trans.ru = apps/routerconsole/locale/messages_ru.po
trans.sv_SE = apps/routerconsole/locale/messages_sv.po
trans.uk_UA = apps/routerconsole/locale/messages_uk.po
@@ -48,10 +53,11 @@ trans.es = apps/i2psnark/locale/messages_es.po
trans.fr = apps/i2psnark/locale/messages_fr.po
trans.hu = apps/i2psnark/locale/messages_hu.po
trans.it = apps/i2psnark/locale/messages_it.po
trans.nb = apps/i2psnark/locale/messages_nb.po
trans.nl = apps/i2psnark/locale/messages_nl.po
trans.pl = apps/i2psnark/locale/messages_pl.po
trans.pt = apps/i2psnark/locale/messages_pt.po
trans.ru = apps/i2psnark/locale/messages_ru.po
trans.ru_RU = apps/i2psnark/locale/messages_ru.po
trans.sv_SE = apps/i2psnark/locale/messages_sv.po
trans.vi = apps/i2psnark/locale/messages_vi.po
trans.zh_CN = apps/i2psnark/locale/messages_zh.po
@@ -70,6 +76,7 @@ trans.hu = apps/susidns/locale/messages_hu.po
trans.it = apps/susidns/locale/messages_it.po
trans.nl = apps/susidns/locale/messages_nl.po
trans.pl = apps/susidns/locale/messages_pl.po
trans.pt = apps/susidns/locale/messages_pt.po
trans.ru = apps/susidns/locale/messages_ru.po
trans.sv_SE = apps/susidns/locale/messages_sv.po
trans.uk_UA = apps/susidns/locale/messages_uk.po
@@ -109,6 +116,7 @@ trans.nl = apps/susimail/locale/messages_nl.po
trans.ru = apps/susimail/locale/messages_ru.po
trans.sv_SE = apps/susimail/locale/messages_sv.po
trans.pl = apps/susimail/locale/messages_pl.po
trans.pt = apps/susimail/locale/messages_pt.po
trans.uk_UA = apps/susimail/locale/messages_uk.po
trans.vi = apps/susimail/locale/messages_vi.po
trans.zh_CN = apps/susimail/locale/messages_zh.po
@@ -120,6 +128,7 @@ trans.cs = debian/po/cs.po
trans.de = debian/po/de.po
trans.el = debian/po/el.po
trans.es = debian/po/es.po
trans.fr = debian/po/fr.po
trans.it = debian/po/it.po
trans.hu = debian/po/hu.po
trans.pl = debian/po/pl.po
@@ -127,6 +136,15 @@ trans.ru = debian/po/ru.po
trans.sv_SE = debian/po/sv.po
trans.uk_UA = debian/po/uk.po
[I2P.i2prouter-script]
source_file = installer/resources/locale/po/messages_en.po
source_lang = en
trans.de = installer/resources/locale/po/messages_de.po
trans.fr = installer/resources/locale/po/messages_fr.po
trans.it = installer/resources/locale/po/messages_it.po
trans.sv_SE = installer/resources/locale/po/messages_sv.po
trans.ru_RU = installer/resources/locale/po/messages_ru.po
[main]
host = http://www.transifex.net

View File

@@ -11,7 +11,7 @@ you may use:
lynx http://localhost:7657/
to configure the router.
If you're having trouble, swing by http://forum.i2p2.de/, check the
If you're having trouble, swing by http://forum.i2p/, check the
website at http://www.i2p2.de/, or get on irc://irc.freenode.net/#i2p
I2P will create and store files and configuration data in the user directory

View File

@@ -72,6 +72,9 @@ Public domain except as listed below:
Copyright (c) 2006, Matthew Estes
See licenses/LICENSE-BlockFile.txt
SipHashInline:
Copyright 2012 Hiroshi Nakamura <nahi@ruby-lang.org>
See licenses/LICENSE-Apache2.0.txt
Router (router.jar):
Public domain except as listed below:
@@ -174,10 +177,11 @@ Applications:
By welterde.
See licenses/LICENSE-GPLv2.txt
Jetty 6.1.26:
Copyright 1995-2009 Mort Bay Consulting Pty Ltd
See licenses/LICENSE-Jetty.txt
Jetty 7.6.10.v20130312:
See licenses/ABOUT-Jetty.html
See licenses/NOTICE-Jetty.html
See licenses/LICENSE-Apache2.0.txt
See licenses/LICENSE-ECLIPSE-1.0.html
See licenses/NOTICE-Commons-Logging.txt
JRobin 1.5.9.1:
@@ -197,6 +201,7 @@ Applications:
- Jersey and EU flag icons: public domain, courtesy Xrmap flag
collection http://www.arvernes.com/wiki/index.php/Xrmap
- Guernsey and Isle of Man flags from the Open Clip Art Library, released into the public domain
- Curaçao, courtesy of David Benbennick, released into the public domain
- All other flag icons: public domain, courtesy mjames@gmail.com http://www.famfamfam.com/
Silk icons: See licenses/LICENSE-SilkIcons.txt
FatCow icons: See licenses/LICENSE-FatCowIcons.txt
@@ -238,8 +243,8 @@ Applications:
Bundles systray4j-2.4.1:
See licenses/LICENSE-LGPLv2.1.txt
Tomcat 6.0.35:
Copyright 1999-2011 The Apache Software Foundation
Tomcat 6.0.36:
Copyright 1999-2012 The Apache Software Foundation
See licenses/LICENSE-Apache2.0.txt
See licenses/NOTICE-Tomcat.txt

View File

@@ -32,7 +32,7 @@ FAQ:
Need help?
IRC irc.freenode.net #i2p
http://forum.i2p2.de/
http://forum.i2p/
Licenses:
See LICENSE.txt

View File

@@ -128,7 +128,7 @@ cat $CWD/slack-desc > $PKG/install/slack-desc
cd $PKG
#
# requiredbuilder fucks up REALLY bad, and thinks java is perl?!
# requiredbuilder messes up REALLY bad, and thinks java is perl?!
# It also did not catch the shell requirements! BOOOOOOOOOOO! HISSSSSSSS!
#
# requiredbuilder -v -y -s $CWD $PKG

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB.Demos.echo.echoclient;
@@ -55,7 +47,7 @@ public class Main {
// exit on anything not legal
break;
}
c = (char)(b & 0x7f); // We only really give a fuck about ASCII
c = (char)(b & 0x7f); // We only care about ASCII
S = new String(S + c);
}
return S;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB.Demos.echo.echoserver;
@@ -52,7 +44,7 @@ public class Main {
if(b < 20) {
break;
}
c = (char)(b & 0x7f); // We only really give a fuck about ASCII
c = (char)(b & 0x7f); // We only care about ASCII
S = new String(S + c);
}
return S;

View File

@@ -83,7 +83,7 @@
<pathelement path="${javac.classpath}" />
</path>
</copy>
<copy todir="${dist.dir}/lib" file="../../installer/lib/jbigi/jbigi.jar" />
<copy todir="${dist.dir}/lib" file="../../build/jbigi.jar" />
<!-- Extract the classes inside the jar files -->
<unjar dest="${dist.dir}/classes" >

View File

@@ -30,11 +30,11 @@ excludes=**/*.html,**/*.txt
file.reference.build-javadoc=../../i2p.i2p/build/javadoc
file.reference.i2p.jar=../../core/java/build/i2p.jar
file.reference.i2ptunnel.jar=../i2ptunnel/java/build/i2ptunnel.jar
file.reference.jbigi.jar=../../installer/lib/jbigi/jbigi.jar
file.reference.jbigi.jar=../../build/jbigi.jar
file.reference.mstreaming.jar=../ministreaming/java/build/mstreaming.jar
file.reference.router.jar=../../router/java/build/router.jar
file.reference.streaming.jar=../streaming/java/build/streaming.jar
file.reference.wrapper.jar=../../installer/lib/wrapper/linux/wrapper.jar
file.reference.wrapper.jar=../../installer/lib/wrapper/all/wrapper.jar
includes=**
jar.compress=true
javac.classpath=\

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;
@@ -94,7 +86,7 @@ public class I2Plistener implements Runnable {
}
} catch (I2PException e) {
// bad shit
// bad stuff
System.out.println("Exception " + e);
}
} finally {

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;
@@ -302,14 +294,14 @@ public class MUXlisten implements Runnable {
// Hopefully nuke stuff here...
{
String boner = tg.getName();
String groupName = tg.getName();
try {
_log.warn("destroySocketManager " + boner);
_log.warn("destroySocketManager " + groupName);
socketManager.destroySocketManager();
_log.warn("destroySocketManager Successful" + boner);
_log.warn("destroySocketManager Successful" + groupName);
} catch (Exception e) {
// nop
_log.warn("destroySocketManager Failed" + boner);
_log.warn("destroySocketManager Failed" + groupName);
_log.warn(e.toString());
}
}
@@ -333,25 +325,25 @@ public class MUXlisten implements Runnable {
// Wait around till all threads are collected.
if (tg != null) {
String boner = tg.getName();
// System.out.println("BOB: MUXlisten: Starting thread collection for: " + boner);
_log.warn("BOB: MUXlisten: Starting thread collection for: " + boner);
String groupName = tg.getName();
// System.out.println("BOB: MUXlisten: Starting thread collection for: " + groupName);
_log.warn("BOB: MUXlisten: Starting thread collection for: " + groupName);
if (tg.activeCount() + tg.activeGroupCount() != 0) {
// visit(tg, 0, boner);
// visit(tg, 0, groupName);
int foo = tg.activeCount() + tg.activeGroupCount();
// hopefully no longer needed!
// int bar = lives;
// System.out.println("BOB: MUXlisten: Waiting on threads for " + boner);
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
// visit(tg, 0, boner);
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + boner + "\n");
// System.out.println("BOB: MUXlisten: Waiting on threads for " + groupName);
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + groupName);
// visit(tg, 0, groupName);
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + groupName + "\n");
// Happily spin forever :-(
while (foo != 0) {
foo = tg.activeCount() + tg.activeGroupCount();
// if (lives != bar && lives != 0) {
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
// visit(tg, 0, boner);
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + boner + "\n");
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + groupName);
// visit(tg, 0, groupName);
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + groupName + "\n");
// }
// bar = lives;
try {
@@ -361,8 +353,8 @@ public class MUXlisten implements Runnable {
}
}
}
// System.out.println("BOB: MUXlisten: Threads went away. Success: " + boner);
_log.warn("BOB: MUXlisten: Threads went away. Success: " + boner);
// System.out.println("BOB: MUXlisten: Threads went away. Success: " + groupName);
_log.warn("BOB: MUXlisten: Threads went away. Success: " + groupName);
tg.destroy();
// Zap reference to the ThreadGroup so the JVM can GC it.
tg = null;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;
@@ -94,7 +86,7 @@ public class TCPtoI2P implements Runnable {
// exit on anything not legal
break;
}
c = (char) (b & 0x7f); // We only really give a fuck about ASCII
c = (char) (b & 0x7f); // We only care about ASCII
S = new String(S + c);
}
return S;

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,7 +11,7 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.BOB;

View File

@@ -37,6 +37,7 @@ import java.util.Map;
import net.i2p.util.SecureFile;
import net.i2p.util.SecureFileOutputStream;
import net.i2p.util.SystemVersion;
/**
* Utility class providing methods to parse and write files in config file
@@ -49,7 +50,7 @@ import net.i2p.util.SecureFileOutputStream;
*/
class ConfigParser {
private static final boolean isWindows = System.getProperty("os.name").startsWith("Win");
private static final boolean isWindows = SystemVersion.isWindows();
/**
* Strip the comments from a String. Lines that begin with '#' and ';' are

View File

@@ -230,7 +230,7 @@ public class Daemon {
*/
public static void update(Map<String, String> settings, String home) {
File published = null;
boolean should_publish = Boolean.valueOf(settings.get("should_publish")).booleanValue();
boolean should_publish = Boolean.parseBoolean(settings.get("should_publish"));
if (should_publish)
published = new File(home, settings
.get("published_addressbook"));
@@ -261,7 +261,7 @@ public class Daemon {
// If false, add hosts via naming service; if true, write hosts.txt file directly
// Default false
if (Boolean.valueOf(settings.get("update_direct")).booleanValue()) {
if (Boolean.parseBoolean(settings.get("update_direct"))) {
// Direct hosts.txt access
File routerFile = new File(home, settings.get("router_addressbook"));
AddressBook master;

View File

@@ -42,8 +42,8 @@ import javax.servlet.http.HttpServletResponse;
*/
public class Servlet extends HttpServlet {
private DaemonThread thread;
private String nonce;
private static final String PROP_NONCE = "addressbook.nonce";
//private String nonce;
//private static final String PROP_NONCE = "addressbook.nonce";
/**
* Hack to allow susidns to kick the daemon when the subscription list changes.
@@ -54,15 +54,15 @@ public class Servlet extends HttpServlet {
*/
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
//System.err.println("Got request nonce = " + request.getParameter("nonce"));
if (this.thread != null && request.getParameter("wakeup") != null &&
this.nonce != null && this.nonce.equals(request.getParameter("nonce"))) {
//System.err.println("Sending interrupt");
this.thread.interrupt();
// no output
} else {
//if (this.thread != null && request.getParameter("wakeup") != null &&
// this.nonce != null && this.nonce.equals(request.getParameter("nonce"))) {
// //System.err.println("Sending interrupt");
// this.thread.interrupt();
// // no output
//} else {
PrintWriter out = response.getWriter();
out.write("I2P addressbook OK");
}
//}
}
/* (non-Javadoc)
@@ -75,9 +75,9 @@ public class Servlet extends HttpServlet {
} catch (ServletException exp) {
System.err.println("Addressbook init exception: " + exp);
}
this.nonce = "" + Math.abs((new Random()).nextLong());
//this.nonce = "" + Math.abs((new Random()).nextLong());
// put the nonce where susidns can get it
System.setProperty(PROP_NONCE, this.nonce);
//System.setProperty(PROP_NONCE, this.nonce);
String[] args = new String[1];
args[0] = config.getInitParameter("home");
this.thread = new DaemonThread(args);

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry combineaccessrules="false" kind="src" path="/i2p_router"/>
<classpathentry combineaccessrules="false" kind="src" path="/i2p_sdk"/>
<classpathentry kind="lib" path="/lib/wrapper/all/wrapper.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="build"/>
</classpath>

17
apps/desktopgui/.project Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>desktopgui</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -8,12 +8,15 @@
<property name="resources" value="resources"/>
<property name="javadoc" value="javadoc"/>
<condition property="no.bundle">
<isfalse value="${require.gettext}" />
</condition>
<property name="javac.compilerargs" value=""/>
<property name="require.gettext" value="true" />
<target name="init">
<mkdir dir="${build}"/>
<mkdir dir="${build}/${resources}"/>
<mkdir dir="${build}"/>
<mkdir dir="${build}/${resources}"/>
<mkdir dir="${build}/${javadoc}"/>
<mkdir dir="${dist}"/>
</target>
@@ -39,7 +42,7 @@
</copy>
</target>
<target name="bundle" >
<target name="bundle" unless="no.bundle">
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="${require.gettext}" >
<arg value="./bundle-messages.sh" />
</exec>

View File

@@ -1,3 +1,4 @@
#!/bin/sh
#
# Update messages_xx.po and messages_xx.class files,
# from both java and jsp sources.

View File

@@ -1,106 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="all" name="fortuna">
<property name="cvs.base.dir" value="java/gnu-crypto" />
<property name="cvs.etc.dir" value="${cvs.base.dir}/etc" />
<property name="cvs.lib.dir" value="${cvs.base.dir}/lib" />
<property name="cvs.object.dir" value="${cvs.base.dir}/classes" />
<property name="cvs.base.crypto.object.dir" value="${cvs.object.dir}/gnu/crypto" />
<property name="cvs.cipher.object.dir" value="${cvs.base.crypto.object.dir}/cipher" />
<property name="cvs.hash.object.dir" value="${cvs.base.crypto.object.dir}/hash" />
<property name="cvs.prng.object.dir" value="${cvs.base.crypto.object.dir}/prng" />
<patternset id="fortuna.files">
<include name="${cvs.base.crypto.object.dir}/Registry.class"/>
<include name="${cvs.prng.object.dir}/Fortuna*.class"/>
<include name="${cvs.prng.object.dir}/BasePRNG.class"/>
<include name="${cvs.prng.object.dir}/RandomEventListener.class"/>
<include name="${cvs.prng.object.dir}/IRandom.class"/>
<include name="${cvs.cipher.object.dir}/CipherFactory.class"/>
<include name="${cvs.cipher.object.dir}/IBlockCipher.class"/>
<include name="${cvs.hash.object.dir}/HashFactory.class"/>
<include name="${cvs.hash.object.dir}/IMessageDigest.class"/>
</patternset>
<target name="all" depends="build,jar"
description="Create and test the custom Fortuna library" />
<target name="build" depends="-init,checkout"
description="Build the source and tests">
<ant dir="${cvs.base.dir}" target="jar" />
</target>
<target name="builddep" />
<target name="checkout" depends="-init" unless="cvs.source.available"
description="Check out GNU Crypto sources from CVS HEAD">
<cvs cvsRoot=":ext:anoncvs@savannah.gnu.org:/cvsroot/gnu-crypto"
cvsRsh="ssh"
dest="java"
package="gnu-crypto" />
</target>
<target name="clean"
description="Remove generated tests and object files">
<ant dir="${cvs.base.dir}" target="clean" />
</target>
<target name="cleandep" />
<target name="compile" />
<target name="distclean" depends="clean"
description="Remove all generated files">
<delete dir="build" />
<delete dir="jartemp" />
<!--
Annoyingly the GNU Crypto distclean task called here doesn't clean
*all* derived files from java/gnu-crypto/lib like it should.....
-->
<ant dir="${cvs.base.dir}" target="distclean" />
<!--
.....and so we mop up the rest ourselves.
-->
<delete dir="${cvs.lib.dir}" />
</target>
<target name="-init">
<available property="cvs.source.available" file="${cvs.base.dir}" />
</target>
<target name="jar" depends="build"
description="Create the custom Fortuna jar library">
<delete dir="build" />
<delete dir="jartemp" />
<mkdir dir="build" />
<mkdir dir="jartemp/${cvs.object.dir}" />
<copy todir="jartemp">
<fileset dir=".">
<patternset refid="fortuna.files" />
</fileset>
</copy>
<jar basedir="jartemp/${cvs.object.dir}" jarfile="build/fortuna.jar">
<manifest>
<section name="fortuna">
<attribute name="Implementation-Title" value="I2P Custom GNU Crypto Fortuna Library" />
<attribute name="Implementation-Version" value="CVS HEAD" />
<attribute name="Implementation-Vendor" value="Free Software Foundation" />
<attribute name="Implementation-Vendor-Id" value="FSF" />
<attribute name="Implementation-URL" value="http://www.gnu.org/software/gnu-crypto" />
</section>
</manifest>
</jar>
<delete dir="jartemp" />
</target>
<target name="test" depends="jar"
description="Perform crypto tests on custom Fortuna jar library" />
<!--
Add this when Fortuna tests are added to GNU Crypto, else write some
-->
<target name="update" depends="checkout"
description="Update GNU Crypto sources to latest CVS HEAD">
<cvs command="update -d" cvsRsh="ssh" dest="java/gnu-crypto" />
</target>
</project>

11
apps/i2psnark/.classpath Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="java/src"/>
<classpathentry combineaccessrules="false" kind="src" path="/i2p_sdk"/>
<classpathentry combineaccessrules="false" kind="src" path="/ministreaming"/>
<classpathentry kind="lib" path="/jetty/jettylib/javax.servlet.jar"/>
<classpathentry kind="lib" path="/jetty/jettylib/jetty-util.jar"/>
<classpathentry kind="lib" path="/jetty/jettylib/org.mortbay.jetty.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="java/build/obj"/>
</classpath>

17
apps/i2psnark/.project Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>i2psnark</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -19,11 +19,15 @@
<pathelement location="../../ministreaming/java/build/obj" />
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
<pathelement location="../../jetty/jettylib/jetty-servlet.jar" />
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
</classpath>
</depend>
</target>
<condition property="no.bundle">
<isfalse value="${require.gettext}" />
</condition>
<property name="javac.compilerargs" value="" />
<property name="require.gettext" value="true" />
@@ -35,7 +39,7 @@
debug="true" deprecation="on" source="1.5" target="1.5"
destdir="./build/obj"
includeAntRuntime="false"
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../jetty/jettylib/jetty-util.jar:../../ministreaming/java/build/mstreaming.jar" >
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../jetty/jettylib/jetty-servlet.jar:../../jetty/jettylib/jetty-util.jar:../../ministreaming/java/build/mstreaming.jar" >
<compilerarg line="${javac.compilerargs}" />
</javac>
</target>
@@ -57,7 +61,7 @@
<target name="jar" depends="builddep, compile, jarUpToDate, listChangedFiles" unless="jar.uptodate" >
<!-- set if unset -->
<property name="workspace.changes.tr" value="" />
<jar destfile="./build/i2psnark.jar" basedir="./build/obj" includes="**/*.class" excludes="**/I2PSnarkServlet*.class **/FetchAndAdd*.class **/messages_*.class">
<jar destfile="./build/i2psnark.jar" basedir="./build/obj" includes="**/*.class" excludes="**/web/* **/messages_*.class">
<manifest>
<attribute name="Main-Class" value="org.klomp.snark.Snark" />
<attribute name="Class-Path" value="i2p.jar mstreaming.jar streaming.jar" />
@@ -72,7 +76,7 @@
<target name="jarUpToDate">
<uptodate property="jar.uptodate" targetfile="build/i2psnark.jar" >
<srcfiles dir= "build/obj" includes="**/*.class" excludes="**/I2PSnarkServlet*.class **/FetchAndAdd*.class **/messages_*.class" />
<srcfiles dir= "build/obj" includes="**/*.class" excludes="**/web/* **/messages_*.class" />
</uptodate>
<condition property="shouldListChanges" >
<and>
@@ -80,7 +84,7 @@
<isset property="jar.uptodate" />
</not>
<not>
<isset property="wjar.uptodate" />
<isset property="war.uptodate" />
</not>
<isset property="mtn.available" />
</and>
@@ -100,9 +104,11 @@
<copy todir="build/icons/.icons" >
<fileset dir="../icons/" />
</copy>
<!-- mime.properties must be in with the classes -->
<copy file="../mime.properties" todir="build/obj/org/klomp/snark/web" />
<war destfile="../i2psnark.war" webxml="../web.xml" >
<!-- include only the web stuff, as of 0.7.12 the router will add i2psnark.jar to the classpath for the war -->
<classes dir="./build/obj" includes="**/web/*.class" />
<classes dir="./build/obj" includes="**/web/*" />
<fileset dir="build/icons/" />
<manifest>
<attribute name="Implementation-Version" value="${full.version}" />
@@ -120,7 +126,7 @@
</uptodate>
</target>
<target name="bundle" depends="compile">
<target name="bundle" depends="compile" unless="no.bundle">
<!-- Update the messages_*.po files.
We need to supply the bat file for windows, and then change the fail property to true -->
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="${require.gettext}" >

View File

@@ -1,3 +1,4 @@
#!/bin/sh
#
# Update messages_xx.po and messages_xx.class files,
# from both java and jsp sources.

View File

@@ -14,7 +14,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -24,6 +23,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.SimpleDataStructure;
import net.i2p.util.LHMCache;
import net.i2p.util.Log;
/**
@@ -209,10 +209,10 @@ public class KBucketSet<T extends SimpleDataStructure> {
int s1, e1, s2, e2;
s1 = b0.getRangeBegin();
e2 = b0.getRangeEnd();
if (B_FACTOR > 1 &&
(s1 & (B_FACTOR - 1)) == 0 &&
((e2 + 1) & (B_FACTOR - 1)) == 0 &&
e2 > s1 + B_FACTOR) {
if (B_VALUE == 1 ||
((s1 & (B_FACTOR - 1)) == 0 &&
((e2 + 1) & (B_FACTOR - 1)) == 0 &&
e2 > s1 + B_FACTOR)) {
// The bucket is a "whole" kbucket with a range > B_FACTOR,
// so it should be split into two "whole" kbuckets each with
// a range >= B_FACTOR.
@@ -518,6 +518,7 @@ public class KBucketSet<T extends SimpleDataStructure> {
/**
* For every bucket that hasn't been updated in this long,
* or isn't close to full,
* generate a random key that would be a member of that bucket.
* The returned keys may be searched for to "refresh" the buckets.
* @return non-null, closest first
@@ -528,7 +529,10 @@ public class KBucketSet<T extends SimpleDataStructure> {
getReadLock();
try {
for (KBucket b : _buckets) {
if (b.getLastChanged() < old)
int curSize = b.getKeyCount();
// Always explore the closest bucket
if ((b.getRangeBegin() == 0) ||
(b.getLastChanged() < old || curSize < BUCKET_SIZE * 3 / 4))
rv.add(generateRandomKey(b));
}
} finally { releaseReadLock(); }
@@ -658,7 +662,7 @@ public class KBucketSet<T extends SimpleDataStructure> {
public Range(T us, int bValue) {
_bValue = bValue;
_bigUs = new BigInteger(1, us.getData());
_distanceCache = new LHM(256);
_distanceCache = new LHMCache(256);
}
/** @return 0 to max-1 or -1 for us */
@@ -697,20 +701,6 @@ public class KBucketSet<T extends SimpleDataStructure> {
}
}
private static class LHM<K, V> extends LinkedHashMap<K, V> {
private final int _max;
public LHM(int max) {
super(max, 0.75f, true);
_max = max;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > _max;
}
}
/**
* For Collections.binarySearch.
* getRangeBegin == getRangeEnd.
@@ -772,8 +762,8 @@ public class KBucketSet<T extends SimpleDataStructure> {
public String toString() {
StringBuilder buf = new StringBuilder(1024);
buf.append("Bucket set rooted on: ").append(_us.toString())
.append(" K= ").append(BUCKET_SIZE)
.append(" B= ").append(B_VALUE)
.append(" K=").append(BUCKET_SIZE)
.append(" B=").append(B_VALUE)
.append(" with ").append(size())
.append(" keys in ").append(_buckets.size()).append(" buckets:\n");
getReadLock();

View File

@@ -39,7 +39,6 @@ public class BitField
this.size = size;
int arraysize = ((size-1)/8)+1;
bitfield = new byte[arraysize];
this.count = 0;
}
/**
@@ -60,7 +59,6 @@ public class BitField
// cleared or clear them explicitly ourselves.
System.arraycopy(bitfield, 0, this.bitfield, 0, arraysize);
this.count = 0;
for (int i = 0; i < size; i++)
if (get(i))
this.count++;
@@ -99,9 +97,11 @@ public class BitField
throw new IndexOutOfBoundsException(Integer.toString(bit));
int index = bit/8;
int mask = 128 >> (bit % 8);
if ((bitfield[index] & mask) == 0) {
count++;
bitfield[index] |= mask;
synchronized(this) {
if ((bitfield[index] & mask) == 0) {
count++;
bitfield[index] |= mask;
}
}
}

View File

@@ -0,0 +1,60 @@
/* CompleteListener - Callback for Snark events
Copyright (C) 2003 Mark J. Wielaard
This file is part of Snark.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.klomp.snark;
/**
* Callback for Snark events.
* @since 0.9.4 moved from Snark.java
*/
public interface CompleteListener {
public void torrentComplete(Snark snark);
public void updateStatus(Snark snark);
/**
* We transitioned from magnet mode, we have now initialized our
* metainfo and storage. The listener should now call getMetaInfo()
* and save the data to disk.
*
* @return the new name for the torrent or null on error
* @since 0.8.4
*/
public String gotMetaInfo(Snark snark);
/**
* @since 0.9
*/
public void fatal(Snark snark, String error);
/**
* @since 0.9.2
*/
public void addMessage(Snark snark, String message);
/**
* @since 0.9.4
*/
public void gotPiece(Snark snark);
// not really listeners but the easiest way to get back to an optional SnarkManager
public long getSavedTorrentTime(Snark snark);
public BitField getSavedTorrentBitField(Snark snark);
}

View File

@@ -39,7 +39,7 @@ import net.i2p.util.SimpleTimer;
/**
* Accepts connections on a TCP port and routes them to sub-acceptors.
*/
public class ConnectionAcceptor implements Runnable
class ConnectionAcceptor implements Runnable
{
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ConnectionAcceptor.class);
private I2PServerSocket serverSocket;

View File

@@ -1,5 +1,7 @@
package org.klomp.snark;
import net.i2p.data.ByteArray;
/**
* Callback used to fetch data
* @since 0.8.2
@@ -10,5 +12,5 @@ interface DataLoader
* This is the callback that PeerConnectionOut calls to get the data from disk
* @return bytes or null for errors
*/
public byte[] loadData(int piece, int begin, int length);
public ByteArray loadData(int piece, int begin, int length);
}

View File

@@ -1,5 +1,6 @@
package org.klomp.snark;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -48,6 +49,7 @@ import org.klomp.snark.dht.KRPC;
public class I2PSnarkUtil {
private final I2PAppContext _context;
private final Log _log;
private final String _baseName;
private boolean _shouldProxy;
private String _proxyHost;
@@ -58,7 +60,7 @@ public class I2PSnarkUtil {
private volatile I2PSocketManager _manager;
private boolean _configured;
private volatile boolean _connecting;
private final Set<Hash> _shitlist;
private final Set<Hash> _banlist;
private int _maxUploaders;
private int _maxUpBW;
private int _maxConnections;
@@ -78,15 +80,24 @@ public class I2PSnarkUtil {
public static final int DEFAULT_MAX_UP_BW = 8; //KBps
public static final int MAX_CONNECTIONS = 16; // per torrent
public static final String PROP_MAX_BW = "i2cp.outboundBytesPerSecond";
public static final boolean DEFAULT_USE_DHT = false;
public static final boolean DEFAULT_USE_DHT = true;
public I2PSnarkUtil(I2PAppContext ctx) {
this(ctx, "i2psnark");
}
/**
* @param baseName generally "i2psnark"
* @since Jetty 7
*/
public I2PSnarkUtil(I2PAppContext ctx, String baseName) {
_context = ctx;
_log = _context.logManager().getLog(Snark.class);
_baseName = baseName;
_opts = new HashMap();
//setProxy("127.0.0.1", 4444);
setI2CPConfig("127.0.0.1", 7654, null);
_shitlist = new ConcurrentHashSet();
_banlist = new ConcurrentHashSet();
_maxUploaders = Snark.MAX_TOTAL_UPLOADERS;
_maxUpBW = DEFAULT_MAX_UP_BW;
_maxConnections = MAX_CONNECTIONS;
@@ -98,7 +109,7 @@ public class I2PSnarkUtil {
// This is used for both announce replies and .torrent file downloads,
// so it must be available even if not connected to I2CP.
// so much for multiple instances
_tmpDir = new SecureDirectory(ctx.getTempDir(), "i2psnark");
_tmpDir = new SecureDirectory(ctx.getTempDir(), baseName);
FileUtil.rmdir(_tmpDir, false);
_tmpDir.mkdirs();
}
@@ -215,9 +226,11 @@ public class I2PSnarkUtil {
}
}
if (opts.getProperty("inbound.nickname") == null)
opts.setProperty("inbound.nickname", "I2PSnark");
opts.setProperty("inbound.nickname", _baseName.replace("i2psnark", "I2PSnark"));
if (opts.getProperty("outbound.nickname") == null)
opts.setProperty("outbound.nickname", "I2PSnark");
opts.setProperty("outbound.nickname", _baseName.replace("i2psnark", "I2PSnark"));
if (opts.getProperty("outbound.priority") == null)
opts.setProperty("outbound.priority", "-10");
// Dont do this for now, it is set in I2PSocketEepGet for announces,
// we don't need fast handshake for peer connections.
//if (opts.getProperty("i2p.streaming.connectDelay") == null)
@@ -244,11 +257,13 @@ public class I2PSnarkUtil {
opts.setProperty("i2p.streaming.maxConnsPerHour", "20");
if (opts.getProperty("i2p.streaming.enforceProtocol") == null)
opts.setProperty("i2p.streaming.enforceProtocol", "true");
if (opts.getProperty("i2p.streaming.disableRejectLogging") == null)
opts.setProperty("i2p.streaming.disableRejectLogging", "true");
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
_connecting = false;
}
if (_shouldUseDHT && _manager != null && _dht == null)
_dht = new KRPC(_context, _manager.getSession());
_dht = new KRPC(_context, _baseName, _manager.getSession());
return (_manager != null);
}
@@ -283,7 +298,7 @@ public class I2PSnarkUtil {
I2PSocketManager mgr = _manager;
// FIXME this can cause race NPEs elsewhere
_manager = null;
_shitlist.clear();
_banlist.clear();
if (mgr != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Disconnecting from I2P", new Exception("I did it"));
@@ -306,24 +321,24 @@ public class I2PSnarkUtil {
if (addr.equals(getMyDestination()))
throw new IOException("Attempt to connect to myself");
Hash dest = addr.calculateHash();
if (_shitlist.contains(dest))
throw new IOException("Not trying to contact " + dest.toBase64() + ", as they are shitlisted");
if (_banlist.contains(dest))
throw new IOException("Not trying to contact " + dest.toBase64() + ", as they are banlisted");
try {
I2PSocket rv = _manager.connect(addr);
if (rv != null)
_shitlist.remove(dest);
_banlist.remove(dest);
return rv;
} catch (I2PException ie) {
_shitlist.add(dest);
_context.simpleScheduler().addEvent(new Unshitlist(dest), 10*60*1000);
_banlist.add(dest);
_context.simpleScheduler().addEvent(new Unbanlist(dest), 10*60*1000);
throw new IOException("Unable to reach the peer " + peer + ": " + ie.getMessage());
}
}
private class Unshitlist implements SimpleTimer.TimedEvent {
private class Unbanlist implements SimpleTimer.TimedEvent {
private Hash _dest;
public Unshitlist(Hash dest) { _dest = dest; }
public void timeReached() { _shitlist.remove(_dest); }
public Unbanlist(Hash dest) { _dest = dest; }
public void timeReached() { _banlist.remove(_dest); }
}
/**
@@ -391,6 +406,46 @@ public class I2PSnarkUtil {
}
}
/**
* Fetch to memory
* @param retries if < 0, set timeout to a few seconds
* @param initialSize buffer size
* @param maxSize fails if greater
* @return null on error
* @since 0.9.4
*/
public byte[] get(String url, boolean rewrite, int retries, int initialSize, int maxSize) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Fetching [" + url + "] to memory");
String fetchURL = url;
if (rewrite)
fetchURL = rewriteAnnounce(url);
int timeout;
if (retries < 0) {
if (!connected())
return null;
timeout = EEPGET_CONNECT_TIMEOUT_SHORT;
retries = 0;
} else {
timeout = EEPGET_CONNECT_TIMEOUT;
if (!connected()) {
if (!connect())
return null;
}
}
ByteArrayOutputStream out = new ByteArrayOutputStream(initialSize);
EepGet get = new I2PSocketEepGet(_context, _manager, retries, -1, maxSize, null, out, fetchURL);
if (get.fetch(timeout)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Fetch successful [" + url + "]: size=" + out.size());
return out.toByteArray();
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Fetch failed [" + url + "]");
return null;
}
}
public I2PServerSocket getServerSocket() {
I2PSocketManager mgr = _manager;
if (mgr != null)
@@ -521,6 +576,15 @@ public class I2PSnarkUtil {
return Collections.EMPTY_LIST;
return _openTrackers;
}
/**
* List of open trackers to use as backups even if disabled
* @return non-null
* @since 0.9.4
*/
public List<String> getBackupTrackers() {
return _openTrackers;
}
public void setUseOpenTrackers(boolean yes) {
_shouldUseOT = yes;
@@ -534,7 +598,7 @@ public class I2PSnarkUtil {
public synchronized void setUseDHT(boolean yes) {
_shouldUseDHT = yes;
if (yes && _manager != null && _dht == null) {
_dht = new KRPC(_context, _manager.getSession());
_dht = new KRPC(_context, _baseName, _manager.getSession());
} else if (!yes && _dht != null) {
_dht.stop();
_dht = null;

View File

@@ -0,0 +1,212 @@
package org.klomp.snark;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import net.i2p.data.Base32;
/**
*
* @since 0.9.4 moved from I2PSnarkServlet
*/
public class MagnetURI {
private final String _tracker;
private final String _name;
private final byte[] _ih;
/** BEP 9 */
public static final String MAGNET = "magnet:";
public static final String MAGNET_FULL = MAGNET + "?xt=urn:btih:";
/** http://sponge.i2p/files/maggotspec.txt */
public static final String MAGGOT = "maggot://";
/**
* @param url non-null
*/
public MagnetURI(I2PSnarkUtil util, String url) throws IllegalArgumentException {
String ihash;
String name;
String trackerURL = null;
if (url.startsWith(MAGNET)) {
// magnet:?xt=urn:btih:0691e40aae02e552cfcb57af1dca56214680c0c5&tr=http://tracker2.postman.i2p/announce.php
String xt = getParam("xt", url);
if (xt == null || !xt.startsWith("urn:btih:"))
throw new IllegalArgumentException();
ihash = xt.substring("urn:btih:".length());
trackerURL = getTrackerParam(url);
name = util.getString("Magnet") + ' ' + ihash;
String dn = getParam("dn", url);
if (dn != null)
name += " (" + Storage.filterName(dn) + ')';
} else if (url.startsWith(MAGGOT)) {
// maggot://0691e40aae02e552cfcb57af1dca56214680c0c5:0b557bbdf8718e95d352fbe994dec3a383e2ede7
ihash = url.substring(MAGGOT.length()).trim();
int col = ihash.indexOf(':');
if (col >= 0)
ihash = ihash.substring(0, col);
name = util.getString("Magnet") + ' ' + ihash;
} else {
throw new IllegalArgumentException();
}
byte[] ih = null;
if (ihash.length() == 32) {
ih = Base32.decode(ihash);
} else if (ihash.length() == 40) {
// Like DataHelper.fromHexString() but ensures no loss of leading zero bytes
ih = new byte[20];
try {
for (int i = 0; i < 20; i++) {
ih[i] = (byte) (Integer.parseInt(ihash.substring(i*2, (i*2) + 2), 16) & 0xff);
}
} catch (NumberFormatException nfe) {
ih = null;
}
}
if (ih == null || ih.length != 20)
throw new IllegalArgumentException();
_ih = ih;
_name = name;
_tracker = trackerURL;
}
/**
* @return 20 bytes or null
*/
public byte[] getInfoHash() {
return _ih;
}
/**
* @return pretty name or null
*/
public String getName() {
return _name;
}
/**
* @return tracker url or null
*/
public String getTrackerURL() {
return _tracker;
}
/**
* @return first decoded parameter or null
*/
private static String getParam(String key, String uri) {
int idx = uri.indexOf('?' + key + '=');
if (idx >= 0) {
idx += key.length() + 2;
} else {
idx = uri.indexOf('&' + key + '=');
if (idx >= 0)
idx += key.length() + 2;
}
if (idx < 0 || idx > uri.length())
return null;
String rv = uri.substring(idx);
idx = rv.indexOf('&');
if (idx >= 0)
rv = rv.substring(0, idx);
else
rv = rv.trim();
return decode(rv);
}
/**
* @return all decoded parameters or null
* @since 0.9.1
*/
private static List<String> getMultiParam(String key, String uri) {
int idx = uri.indexOf('?' + key + '=');
if (idx >= 0) {
idx += key.length() + 2;
} else {
idx = uri.indexOf('&' + key + '=');
if (idx >= 0)
idx += key.length() + 2;
}
if (idx < 0 || idx > uri.length())
return null;
List<String> rv = new ArrayList();
while (true) {
String p = uri.substring(idx);
uri = p;
idx = p.indexOf('&');
if (idx >= 0)
p = p.substring(0, idx);
else
p = p.trim();
rv.add(decode(p));
idx = uri.indexOf('&' + key + '=');
if (idx < 0)
break;
idx += key.length() + 2;
}
return rv;
}
/**
* @return first valid I2P tracker or null
* @since 0.9.1
*/
private static String getTrackerParam(String uri) {
List<String> trackers = getMultiParam("tr", uri);
if (trackers == null)
return null;
for (String t : trackers) {
try {
URI u = new URI(t);
String protocol = u.getScheme();
String host = u.getHost();
if (protocol == null || host == null ||
!protocol.toLowerCase(Locale.US).equals("http") ||
!host.toLowerCase(Locale.US).endsWith(".i2p"))
continue;
return t;
} catch(URISyntaxException use) {}
}
return null;
}
/**
* Decode %xx encoding, convert to UTF-8 if necessary
* Copied from i2ptunnel LocalHTTPServer
* @since 0.9.1
*/
private static String decode(String s) {
if (!s.contains("%"))
return s;
StringBuilder buf = new StringBuilder(s.length());
boolean utf8 = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c != '%') {
buf.append(c);
} else {
try {
int val = Integer.parseInt(s.substring(++i, (++i) + 1), 16);
if ((val & 0x80) != 0)
utf8 = true;
buf.append((char) val);
} catch (IndexOutOfBoundsException ioobe) {
break;
} catch (NumberFormatException nfe) {
break;
}
}
}
if (utf8) {
try {
return new String(buf.toString().getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException uee) {}
}
return buf.toString();
}
}

View File

@@ -23,8 +23,13 @@ package org.klomp.snark;
import java.io.DataOutputStream;
import java.io.IOException;
// Used to queue outgoing connections
// sendMessage() should be used to translate them to wire format.
import net.i2p.data.ByteArray;
import net.i2p.util.ByteCache;
/**
* Used to queue outgoing connections
* sendMessage() should be used to translate them to wire format.
*/
class Message
{
final static byte KEEP_ALIVE = -1;
@@ -69,6 +74,9 @@ class Message
// now unused
//SimpleTimer.TimedEvent expireEvent;
private static final int BUFSIZE = PeerState.PARTSIZE;
private static final ByteCache _cache = ByteCache.getInstance(16, BUFSIZE);
/** Utility method for sending a message through a DataStream. */
void sendMessage(DataOutputStream dos) throws IOException
{
@@ -79,11 +87,15 @@ class Message
return;
}
ByteArray ba;
// Get deferred data
if (data == null && dataLoader != null) {
data = dataLoader.loadData(piece, begin, length);
if (data == null)
ba = dataLoader.loadData(piece, begin, length);
if (ba == null)
return; // hmm will get retried, but shouldn't happen
data = ba.getData();
} else {
ba = null;
}
// Calculate the total length in bytes
@@ -139,6 +151,10 @@ class Message
// Send actual data
if (type == BITFIELD || type == PIECE || type == EXTENSION)
dos.write(data, off, len);
// Was pulled from cache in Storage.getPiece() via dataLoader
if (ba != null && ba.getData().length == BUFSIZE)
_cache.release(ba, false);
}
@Override

View File

@@ -61,6 +61,7 @@ public class MetaInfo
private final byte[] piece_hashes;
private final long length;
private final boolean privateTorrent;
private final List<List<String>> announce_list;
private Map<String, BEValue> infoMap;
/**
@@ -69,9 +70,11 @@ public class MetaInfo
* @param announce may be null
* @param files null for single-file torrent
* @param lengths null for single-file torrent
* @param announce_list may be null
*/
MetaInfo(String announce, String name, String name_utf8, List<List<String>> files, List<Long> lengths,
int piece_length, byte[] piece_hashes, long length, boolean privateTorrent)
int piece_length, byte[] piece_hashes, long length, boolean privateTorrent,
List<List<String>> announce_list)
{
this.announce = announce;
this.name = name;
@@ -83,6 +86,7 @@ public class MetaInfo
this.piece_hashes = piece_hashes;
this.length = length;
this.privateTorrent = privateTorrent;
this.announce_list = announce_list;
// TODO if we add a parameter for other keys
//if (other != null) {
@@ -141,6 +145,23 @@ public class MetaInfo
this.announce = val.getString();
}
// BEP 12
val = m.get("announce-list");
if (val == null) {
this.announce_list = null;
} else {
this.announce_list = new ArrayList();
List<BEValue> bl1 = val.getList();
for (BEValue bev : bl1) {
List<BEValue> bl2 = bev.getList();
List<String> sl2 = new ArrayList();
for (BEValue bev2 : bl2) {
sl2.add(bev2.getString());
}
this.announce_list.add(sl2);
}
}
val = m.get("info");
if (val == null)
throw new InvalidBEncodingException("Missing info map");
@@ -296,6 +317,15 @@ public class MetaInfo
return announce;
}
/**
* Returns a list of lists of urls.
*
* @since 0.9.5
*/
public List<List<String>> getAnnounceList() {
return announce_list;
}
/**
* Returns the original 20 byte SHA1 hash over the bencoded info map.
*/
@@ -470,12 +500,13 @@ public class MetaInfo
/**
* Creates a copy of this MetaInfo that shares everything except the
* announce URL.
* Drops any announce-list.
*/
public MetaInfo reannounce(String announce)
{
return new MetaInfo(announce, name, name_utf8, files,
lengths, piece_length,
piece_hashes, length, privateTorrent);
piece_hashes, length, privateTorrent, null);
}
/**
@@ -486,6 +517,8 @@ public class MetaInfo
Map m = new HashMap();
if (announce != null)
m.put("announce", announce);
if (announce_list != null)
m.put("announce-list", announce_list);
Map info = createInfoMap();
m.put("info", info);
// don't save this locally, we should only do this once

View File

@@ -9,6 +9,8 @@ import java.security.MessageDigest;
import net.i2p.I2PAppContext;
import net.i2p.crypto.SHA1;
import net.i2p.data.ByteArray;
import net.i2p.util.ByteCache;
import net.i2p.util.Log;
import net.i2p.util.SecureFile;
@@ -42,6 +44,9 @@ class PartialPiece implements Comparable {
private final int pclen;
private final File tempDir;
private static final int BUFSIZE = PeerState.PARTSIZE;
private static final ByteCache _cache = ByteCache.getInstance(16, BUFSIZE);
// Any bigger than this, use temp file instead of heap
private static final int MAX_IN_MEM = 128 * 1024;
// May be reduced on OOM
@@ -154,7 +159,16 @@ class PartialPiece implements Comparable {
sha1.update(bs);
} else {
int read = 0;
byte[] buf = new byte[Math.min(pclen, 16384)];
int buflen = Math.min(pclen, BUFSIZE);
ByteArray ba;
byte[] buf;
if (buflen == BUFSIZE) {
ba = _cache.acquire();
buf = ba.getData();
} else {
ba = null;
buf = new byte[buflen];
}
synchronized (this) {
if (raf == null)
throw new IOException();
@@ -167,6 +181,8 @@ class PartialPiece implements Comparable {
sha1.update(buf, 0, rd);
}
}
if (ba != null)
_cache.release(ba, false);
if (read < pclen)
throw new IOException();
}
@@ -182,7 +198,15 @@ class PartialPiece implements Comparable {
din.readFully(bs, off, len);
} else {
// read in fully before synching on raf
byte[] tmp = new byte[len];
ByteArray ba;
byte[] tmp;
if (len == BUFSIZE) {
ba = _cache.acquire();
tmp = ba.getData();
} else {
ba = null;
tmp = new byte[len];
}
din.readFully(tmp);
synchronized (this) {
if (raf == null)
@@ -190,6 +214,8 @@ class PartialPiece implements Comparable {
raf.seek(off);
raf.write(tmp);
}
if (ba != null)
_cache.release(ba, false);
}
}
@@ -208,7 +234,16 @@ class PartialPiece implements Comparable {
out.write(bs, offset, len);
} else {
int read = 0;
byte[] buf = new byte[Math.min(len, 16384)];
int buflen = Math.min(len, BUFSIZE);
ByteArray ba;
byte[] buf;
if (buflen == BUFSIZE) {
ba = _cache.acquire();
buf = ba.getData();
} else {
ba = null;
buf = new byte[buflen];
}
synchronized (this) {
if (raf == null)
throw new IOException();
@@ -220,6 +255,8 @@ class PartialPiece implements Comparable {
out.write(buf, 0, rd);
}
}
if (ba != null)
_cache.release(ba, false);
}
}

View File

@@ -359,7 +359,7 @@ public class Peer implements Comparable
String bittorrentProtocol = new String(bs, "UTF-8");
if (!"BitTorrent protocol".equals(bittorrentProtocol))
throw new IOException("Handshake failure, expected "
+ "'Bittorrent protocol', got '"
+ "'BitTorrent protocol', got '"
+ bittorrentProtocol + "'");
// Handshake read - options

View File

@@ -40,7 +40,7 @@ import net.i2p.util.Log;
* protocol connection. The PeerAcceptor will then create a new peer
* if the PeerCoordinator wants more peers.
*/
public class PeerAcceptor
class PeerAcceptor
{
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerAcceptor.class);
private final PeerCoordinator coordinator;

View File

@@ -437,6 +437,7 @@ class PeerConnectionOut implements Runnable
*/
void sendPiece(int piece, int begin, int length, DataLoader loader)
{
/****
boolean sendNow = false;
// are there any cases where we should?
@@ -447,6 +448,7 @@ class PeerConnectionOut implements Runnable
sendPiece(piece, begin, length, bytes);
return;
}
****/
// queue a fake message... set everything up,
// except save the PeerState instead of the bytes.

View File

@@ -35,6 +35,7 @@ import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.util.ConcurrentHashSet;
@@ -214,7 +215,7 @@ class PeerCoordinator implements PeerListener
public Storage getStorage() { return storage; }
// for web page detailed stats
/** for web page detailed stats */
public List<Peer> peerList()
{
return new ArrayList(peers);
@@ -375,8 +376,11 @@ class PeerCoordinator implements PeerListener
*/
public boolean needOutboundPeers() {
//return wantedBytes != 0 && needPeers();
// minus one to make it a little easier for new peers to get in on large swarms
return wantedBytes != 0 && !halted && peers.size() < getMaxConnections() - 1;
// minus two to make it a little easier for new peers to get in on large swarms
return wantedBytes != 0 &&
!halted &&
peers.size() < getMaxConnections() - 2 &&
(storage == null || !storage.isChecking());
}
/**
@@ -445,6 +449,12 @@ class PeerCoordinator implements PeerListener
synchronized (downloaded_old) {
Arrays.fill(downloaded_old, 0);
}
// failsafe
synchronized(wantedPieces) {
for (Piece pc : wantedPieces) {
pc.clear();
}
}
timer.schedule((CHECK_PERIOD / 2) + _random.nextInt((int) CHECK_PERIOD));
}
@@ -508,8 +518,8 @@ class PeerCoordinator implements PeerListener
peerCount = peers.size();
unchokePeer();
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
}
}
if (toDisconnect != null) {
@@ -645,13 +655,18 @@ class PeerCoordinator implements PeerListener
*/
public boolean gotHave(Peer peer, int piece)
{
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
synchronized(wantedPieces)
{
return wantedPieces.contains(new Piece(piece));
}
synchronized(wantedPieces) {
for (Piece pc : wantedPieces) {
if (pc.getId() == piece) {
pc.addPeer(peer);
return true;
}
}
return false;
}
}
/**
@@ -660,23 +675,20 @@ class PeerCoordinator implements PeerListener
*/
public boolean gotBitField(Peer peer, BitField bitfield)
{
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
synchronized(wantedPieces)
{
Iterator<Piece> it = wantedPieces.iterator();
while (it.hasNext())
{
Piece p = it.next();
boolean rv = false;
synchronized(wantedPieces) {
for (Piece p : wantedPieces) {
int i = p.getId();
if (bitfield.get(i)) {
p.addPeer(peer);
return true;
rv = true;
}
}
}
return false;
}
}
return rv;
}
/**
@@ -732,7 +744,19 @@ class PeerCoordinator implements PeerListener
break;
if (havePieces.get(p.getId()) && !p.isRequested())
{
piece = p;
// never ever choose one that's in partialPieces, or we
// will create a second one and leak
boolean hasPartial = false;
for (PartialPiece pp : partialPieces) {
if (pp.getPiece() == p.getId()) {
if (_log.shouldLog(Log.INFO))
_log.info("wantPiece() skipping partial for " + peer + ": piece = " + pp);
hasPartial = true;
break;
}
}
if (!hasPartial)
piece = p;
}
else if (p.isRequested())
{
@@ -747,8 +771,12 @@ class PeerCoordinator implements PeerListener
// AND if there are almost no wanted pieces left (real end game).
// If we do end game all the time, we generate lots of extra traffic
// when the seeder is super-slow and all the peers are "caught up"
if (wantedSize > END_GAME_THRESHOLD)
if (wantedSize > END_GAME_THRESHOLD) {
if (_log.shouldLog(Log.INFO))
_log.info("Nothing to request, " + requested.size() + " being requested and " +
wantedSize + " still wanted");
return null; // nothing to request and not in end game
}
// let's not all get on the same piece
// Even better would be to sort by number of requests
if (record)
@@ -784,7 +812,8 @@ class PeerCoordinator implements PeerListener
}
if (record) {
if (_log.shouldLog(Log.INFO))
_log.info(peer + " is now requesting: piece " + piece + " priority " + piece.getPriority());
_log.info("Now requesting from " + peer + ": piece " + piece + " priority " + piece.getPriority() +
" peers " + piece.getPeerCount() + '/' + peers.size());
piece.setRequested(peer, true);
}
return piece;
@@ -874,7 +903,7 @@ class PeerCoordinator implements PeerListener
*
* @throws RuntimeException on IOE getting the data
*/
public byte[] gotRequest(Peer peer, int piece, int off, int len)
public ByteArray gotRequest(Peer peer, int piece, int off, int len)
{
if (halted)
return null;
@@ -905,8 +934,8 @@ class PeerCoordinator implements PeerListener
{
uploaded += size;
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
}
/**
@@ -916,8 +945,8 @@ class PeerCoordinator implements PeerListener
{
downloaded += size;
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
}
/**
@@ -929,13 +958,11 @@ class PeerCoordinator implements PeerListener
*/
public boolean gotPiece(Peer peer, PartialPiece pp)
{
if (metainfo == null || storage == null)
if (metainfo == null || storage == null || storage.isChecking() || halted) {
pp.release();
return true;
int piece = pp.getPiece();
if (halted) {
_log.info("Got while-halted piece " + piece + "/" + metainfo.getPieces() +" from " + peer + " for " + metainfo.getName());
return true; // We don't actually care anymore.
}
int piece = pp.getPiece();
synchronized(wantedPieces)
{
@@ -948,12 +975,15 @@ class PeerCoordinator implements PeerListener
// Assume we got a good piece, we don't really care anymore.
// Well, this could be caused by a change in priorities, so
// only return true if we already have it, otherwise might as well keep it.
if (storage.getBitField().get(piece))
if (storage.getBitField().get(piece)) {
pp.release();
return true;
}
}
try
{
// this takes forever if complete, as it rechecks
if (storage.putPiece(pp))
{
if (_log.shouldLog(Log.INFO))
@@ -1026,8 +1056,8 @@ class PeerCoordinator implements PeerListener
if (_log.shouldLog(Log.INFO))
_log.info("Got choke(" + choke + "): " + peer);
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
}
public void gotInterest(Peer peer, boolean interest)
@@ -1046,8 +1076,8 @@ class PeerCoordinator implements PeerListener
}
}
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
}
public void disconnected(Peer peer)
@@ -1067,18 +1097,18 @@ class PeerCoordinator implements PeerListener
peerCount = peers.size();
}
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
}
/** Called when a peer is removed, to prevent it from being used in
* rarest-first calculations.
*/
public void removePeerFromPieces(Peer peer) {
private void removePeerFromPieces(Peer peer) {
synchronized(wantedPieces) {
for(Iterator<Piece> iter = wantedPieces.iterator(); iter.hasNext(); ) {
Piece piece = iter.next();
for (Piece piece : wantedPieces) {
piece.removePeer(peer);
piece.setRequested(peer, false);
}
}
}
@@ -1159,6 +1189,8 @@ class PeerCoordinator implements PeerListener
public PartialPiece getPartialPiece(Peer peer, BitField havePieces) {
if (metainfo == null)
return null;
if (storage != null && storage.isChecking())
return null;
synchronized(wantedPieces) {
// sorts by remaining bytes, least first
Collections.sort(partialPieces);
@@ -1171,11 +1203,24 @@ class PeerCoordinator implements PeerListener
for(Piece piece : wantedPieces) {
if (piece.getId() == savedPiece) {
if (peer.isCompleted() && piece.getPeerCount() > 1) {
// Try to preserve rarest-first when we have only one seeder
// by not preferring a partial piece that others have too
// Try to preserve rarest-first
// by not requesting a partial piece that non-seeders also have
// from a seeder
skipped = true;
break;
boolean nonSeeds = false;
for (Peer pr : peers) {
PeerState state = pr.state;
if (state == null) continue;
BitField bf = state.bitfield;
if (bf == null) continue;
if (bf.get(savedPiece) && !pr.isCompleted()) {
nonSeeds = true;
break;
}
}
if (nonSeeds) {
skipped = true;
break;
}
}
iter.remove();
piece.setRequested(peer, true);
@@ -1250,6 +1295,7 @@ class PeerCoordinator implements PeerListener
PartialPiece pp = iter.next();
if (pp.getPiece() == piece) {
iter.remove();
pp.release();
// there should be only one but keep going to be sure
}
}
@@ -1393,6 +1439,7 @@ class PeerCoordinator implements PeerListener
/**
* Called by TrackerClient
* @return the Set itself, modifiable, not a copy, caller should clear()
* @since 0.8.4
*/
Set<PeerID> getPEXPeers() {

View File

@@ -12,7 +12,7 @@ import net.i2p.crypto.SHA1Hash;
* Each PeerCoordinator is added to the set from within the Snark (and removed
* from it there too)
*/
public class PeerCoordinatorSet {
class PeerCoordinatorSet {
private final Map<SHA1Hash, PeerCoordinator> _coordinators;
public PeerCoordinatorSet() {

View File

@@ -43,7 +43,7 @@ import org.klomp.snark.bencode.InvalidBEncodingException;
* and the PeerID is not required.
* Equality is now determined solely by the dest hash.
*/
public class PeerID implements Comparable
class PeerID implements Comparable
{
private byte[] id;
private Destination address;

View File

@@ -22,6 +22,8 @@ package org.klomp.snark;
import java.util.List;
import net.i2p.data.ByteArray;
/**
* Listener for Peer events.
*/
@@ -114,7 +116,7 @@ interface PeerListener
* @return a byte array containing the piece or null when the piece
* is not available (which is a protocol error).
*/
byte[] gotRequest(Peer peer, int piece, int off, int len);
ByteArray gotRequest(Peer peer, int piece, int off, int len);
/**
* Called when a (partial) piece has been downloaded from the peer.

View File

@@ -27,6 +27,7 @@ import java.util.List;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.util.Log;
class PeerState implements DataLoader
@@ -245,8 +246,8 @@ class PeerState implements DataLoader
* @return bytes or null for errors
* @since 0.8.2
*/
public byte[] loadData(int piece, int begin, int length) {
byte[] pieceBytes = listener.gotRequest(peer, piece, begin, length);
public ByteArray loadData(int piece, int begin, int length) {
ByteArray pieceBytes = listener.gotRequest(peer, piece, begin, length);
if (pieceBytes == null)
{
// XXX - Protocol error-> diconnect?
@@ -256,7 +257,7 @@ class PeerState implements DataLoader
}
// More sanity checks
if (length != pieceBytes.length)
if (length != pieceBytes.getData().length)
{
// XXX - Protocol error-> disconnect?
if (_log.shouldLog(Log.WARN))
@@ -355,22 +356,21 @@ class PeerState implements DataLoader
+ piece + "," + begin + "," + length + ") from "
+ peer);
int r = getFirstOutstandingRequest(piece);
// Unrequested piece number?
if (r == -1)
{
if (_log.shouldLog(Log.INFO))
_log.info("Unrequested 'piece: " + piece + ", "
+ begin + ", " + length + "' received from "
+ peer);
return null;
}
// Lookup the correct piece chunk request from the list.
Request req;
synchronized(this)
{
int r = getFirstOutstandingRequest(piece);
// Unrequested piece number?
if (r == -1) {
if (_log.shouldLog(Log.INFO))
_log.info("Unrequested 'piece: " + piece + ", "
+ begin + ", " + length + "' received from "
+ peer);
return null;
}
req = outstandingRequests.get(r);
while (req.getPiece() == piece && req.off != begin
&& r < outstandingRequests.size() - 1)
@@ -591,6 +591,7 @@ class PeerState implements DataLoader
// Send cancel even when we are choked to make sure that it is
// really never ever send.
out.sendCancel(req);
req.getPartialPiece().release();
}
}
}
@@ -681,6 +682,7 @@ class PeerState implements DataLoader
_log.debug(peer + " addRequest() we are choked, delaying requestNextPiece()");
return;
}
// huh? rv unused
more_pieces = requestNextPiece();
} else if (more_pieces) // We want something
{
@@ -710,6 +712,8 @@ class PeerState implements DataLoader
}
// failsafe
// However this is bad as it thrashes the peer when we change our mind
// Ticket 691 cause here?
if (interesting && lastRequest == null && outstandingRequests.isEmpty())
setInteresting(false);
@@ -737,6 +741,10 @@ class PeerState implements DataLoader
out.sendRequest(r);
lastRequest = r;
return true;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Got dup from coord: " + pp);
pp.release();
}
}
@@ -783,6 +791,8 @@ class PeerState implements DataLoader
}
// failsafe
// However this is bad as it thrashes the peer when we change our mind
// Ticket 691 cause here?
if (outstandingRequests.isEmpty())
lastRequest = null;

View File

@@ -12,13 +12,13 @@ class Piece implements Comparable {
private final int id;
private final Set<PeerID> peers;
/** @since 0.8.3 */
private Set<PeerID> requests;
private volatile Set<PeerID> requests;
/** @since 0.8.1 */
private int priority;
public Piece(int id) {
this.id = id;
this.peers = new HashSet(I2PSnarkUtil.MAX_CONNECTIONS);
this.peers = new HashSet(I2PSnarkUtil.MAX_CONNECTIONS / 2);
// defer creating requests to save memory
}
@@ -54,7 +54,10 @@ class Piece implements Comparable {
/** caller must synchronize */
public boolean addPeer(Peer peer) { return this.peers.add(peer.getPeerID()); }
/** caller must synchronize */
/**
* Caller must synchronize.
* @return true if removed
*/
public boolean removePeer(Peer peer) { return this.peers.remove(peer.getPeerID()); }
/**
@@ -104,6 +107,17 @@ class Piece implements Comparable {
public int getRequestCount() {
return this.requests == null ? 0 : this.requests.size();
}
/**
* Clear all knowledge of peers
* Caller must synchronize
* @since 0.9.3
*/
public void clear() {
peers.clear();
if (requests != null)
requests.clear();
}
/** @return default 0 @since 0.8.1 */
public int getPriority() { return this.priority; }

View File

@@ -688,6 +688,22 @@ public class Snark
starting = true;
}
/**
* File checking in progress.
* @since 0.9.3
*/
public boolean isChecking() {
return storage != null && storage.isChecking();
}
/**
* Disk allocation (ballooning) in progress.
* @since 0.9.3
*/
public boolean isAllocating() {
return storage != null && storage.isAllocating();
}
/**
* @since 0.8.4
*/
@@ -1099,7 +1115,12 @@ public class Snark
}
}
///////////// Begin StorageListener methods
//private boolean allocating = false;
/** does nothing */
public void storageCreateFile(Storage storage, String name, long length)
{
//if (allocating)
@@ -1113,6 +1134,7 @@ public class Snark
// How much storage space has been allocated
private long allocated = 0;
/** does nothing */
public void storageAllocated(Storage storage, long length)
{
//allocating = true;
@@ -1124,7 +1146,8 @@ public class Snark
private boolean allChecked = false;
private boolean checking = false;
private boolean prechecking = true;
//private boolean prechecking = true;
public void storageChecked(Storage storage, int num, boolean checked)
{
//allocating = false;
@@ -1142,6 +1165,8 @@ public class Snark
if (!checking) {
if (_log.shouldLog(Log.INFO))
_log.info("Got " + (checked ? "" : "BAD ") + "piece: " + num);
if (completeListener != null)
completeListener.gotPiece(this);
}
}
@@ -1171,6 +1196,9 @@ public class Snark
coordinator.setWantedPieces();
}
///////////// End StorageListener methods
/** SnarkSnutdown callback unused */
public void shutdown()
{
@@ -1188,34 +1216,6 @@ public class Snark
completeListener.addMessage(this, message);
}
public interface CompleteListener {
public void torrentComplete(Snark snark);
public void updateStatus(Snark snark);
/**
* We transitioned from magnet mode, we have now initialized our
* metainfo and storage. The listener should now call getMetaInfo()
* and save the data to disk.
*
* @return the new name for the torrent or null on error
* @since 0.8.4
*/
public String gotMetaInfo(Snark snark);
/**
* @since 0.9
*/
public void fatal(Snark snark, String error);
/**
* @since 0.9.2
*/
public void addMessage(Snark snark, String message);
// not really listeners but the easiest way to get back to an optional SnarkManager
public long getSavedTorrentTime(Snark snark);
public BitField getSavedTorrentBitField(Snark snark);
}
/** Maintain a configurable total uploader cap
* coordinatorListener

View File

@@ -27,6 +27,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.update.*;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.FileUtil;
import net.i2p.util.I2PAppThread;
@@ -42,7 +43,7 @@ import org.klomp.snark.dht.DHT;
/**
* Manage multiple snarks
*/
public class SnarkManager implements Snark.CompleteListener {
public class SnarkManager implements CompleteListener {
/**
* Map of (canonical) filename of the .torrent file to Snark instance.
@@ -56,6 +57,8 @@ public class SnarkManager implements Snark.CompleteListener {
private /* FIXME final FIXME */ File _configFile;
private Properties _config;
private final I2PAppContext _context;
private final String _contextPath;
private final String _contextName;
private final Log _log;
private final Queue<String> _messages;
private final I2PSnarkUtil _util;
@@ -65,6 +68,8 @@ public class SnarkManager implements Snark.CompleteListener {
private volatile boolean _running;
private volatile boolean _stopping;
private final Map<String, Tracker> _trackerMap;
private UpdateManager _umgr;
private UpdateHandler _uhandler;
public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost";
public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort";
@@ -79,7 +84,7 @@ public class SnarkManager implements Snark.CompleteListener {
public static final String PROP_META_PRIORITY_SUFFIX = ".priority";
public static final String PROP_META_MAGNET_PREFIX = "i2psnark.magnet.";
private static final String CONFIG_FILE = "i2psnark.config";
private static final String CONFIG_FILE_SUFFIX = ".config";
public static final String PROP_FILES_PUBLIC = "i2psnark.filesPublic";
public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops
public static final String DEFAULT_AUTO_START = "false";
@@ -87,6 +92,7 @@ public class SnarkManager implements Snark.CompleteListener {
//public static final String DEFAULT_LINK_PREFIX = "file:///";
public static final String PROP_STARTUP_DELAY = "i2psnark.startupDelay";
public static final String PROP_REFRESH_DELAY = "i2psnark.refreshSeconds";
public static final String PROP_PAGE_SIZE = "i2psnark.pageSize";
public static final String RC_PROP_THEME = "routerconsole.theme";
public static final String RC_PROP_UNIVERSAL_THEMING = "routerconsole.universal.theme";
public static final String PROP_THEME = "i2psnark.theme";
@@ -100,6 +106,7 @@ public class SnarkManager implements Snark.CompleteListener {
public static final int DEFAULT_MAX_UP_BW = 10;
public static final int DEFAULT_STARTUP_DELAY = 3;
public static final int DEFAULT_REFRESH_DELAY_SECS = 60;
private static final int DEFAULT_PAGE_SIZE = 50;
/**
* "name", "announceURL=websiteURL" pairs
@@ -117,7 +124,7 @@ public class SnarkManager implements Snark.CompleteListener {
// , "Galen", "http://5jpwQMI5FT303YwKa5Rd38PYSX04pbIKgTaKQsWbqoWjIfoancFdWCShXHLI5G5ofOb0Xu11vl2VEMyPsg1jUFYSVnu4-VfMe3y4TKTR6DTpetWrnmEK6m2UXh91J5DZJAKlgmO7UdsFlBkQfR2rY853-DfbJtQIFl91tbsmjcA5CGQi4VxMFyIkBzv-pCsuLQiZqOwWasTlnzey8GcDAPG1LDcvfflGV~6F5no9mnuisZPteZKlrv~~TDoXTj74QjByWc4EOYlwqK8sbU9aOvz~s31XzErbPTfwiawiaZ0RUI-IDrKgyvmj0neuFTWgjRGVTH8bz7cBZIc3viy6ioD-eMQOrXaQL0TCWZUelRwHRvgdPiQrxdYQs7ixkajeHzxi-Pq0EMm5Vbh3j3Q9kfUFW3JjFDA-MLB4g6XnjCbM5J1rC0oOBDCIEfhQkszru5cyLjHiZ5yeA0VThgu~c7xKHybv~OMXION7V8pBKOgET7ZgAkw1xgYe3Kkyq5syAAAA.i2p/tr/announce.php=http://galen.i2p/tr/"
"Postman", "http://tracker2.postman.i2p/announce.php=http://tracker2.postman.i2p/"
,"Welterde", "http://tracker.welterde.i2p/a=http://tracker.welterde.i2p/stats?mode=top5"
,"Diftracker", "http://n--XWjHjUPjnMNrSwXA2OYXpMIUL~u4FNXnrt2HtjK3y6j~4SOClyyeKzd0zRPlixxkCe2wfBIYye3bZsaqAD8bd0QMmowxbq91WpjsPfKMiphJbePKXtYAVARiy0cqyvh1d2LyDE-6wkvgaw45hknmS0U-Dg3YTJZbAQRU2SKXgIlAbWCv4R0kDFBLEVpReDiJef3rzAWHiW8yjmJuJilkYjMwlfRjw8xx1nl2s~yhlljk1pl13jGYb0nfawQnuOWeP-ASQWvAAyVgKvZRJE2O43S7iveu9piuv7plXWbt36ef7ndu2GNoNyPOBdpo9KUZ-NOXm4Kgh659YtEibL15dEPAOdxprY0sYUurVw8OIWqrpX7yn08nbi6qHVGqQwTpxH35vkL8qrCbm-ym7oQJQnNmSDrNTyWYRFSq5s5~7DAdFDzqRPW-pX~g0zEivWj5tzkhvG9rVFgFo0bpQX3X0PUAV9Xbyf8u~v8Zbr9K1pCPqBq9XEr4TqaLHw~bfAAAA.i2p/announce.php=http://diftracker.i2p/"
,"Diftracker", "http://diftracker.i2p/announce.php=http://diftracker.i2p/"
// , "CRSTRACK", "http://b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA.i2p/tracker/announce.php=http://crstrack.i2p/tracker/"
// ,"Exotrack", "http://blbgywsjubw3d2zih2giokakhe3o2cko7jtte4risb3hohbcoyva.b32.i2p/announce.php=http://exotrack.i2p/"
};
@@ -125,17 +132,33 @@ public class SnarkManager implements Snark.CompleteListener {
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
public static final String PROP_TRACKERS = "i2psnark.trackers";
/**
* For embedded.
*/
public SnarkManager(I2PAppContext ctx) {
this(ctx, "/i2psnark", "i2psnark");
}
/**
* For webapp.
* @param ctxPath generally "/i2psnark"
* @param ctxName generally "i2psnark"
* @since 0.9.6
*/
public SnarkManager(I2PAppContext ctx, String ctxPath, String ctxName) {
_snarks = new ConcurrentHashMap();
_magnets = new ConcurrentHashSet();
_addSnarkLock = new Object();
_context = ctx;
_contextPath = ctxPath;
_contextName = ctxName;
_log = _context.logManager().getLog(SnarkManager.class);
_messages = new LinkedBlockingQueue();
_util = new I2PSnarkUtil(_context);
_configFile = new File(CONFIG_FILE);
_util = new I2PSnarkUtil(_context, ctxName);
String cfile = ctxName + CONFIG_FILE_SUFFIX;
_configFile = new File(cfile);
if (!_configFile.isAbsolute())
_configFile = new File(_context.getConfigDir(), CONFIG_FILE);
_configFile = new File(_context.getConfigDir(), cfile);
_trackerMap = new ConcurrentHashMap(4);
loadConfig(null);
}
@@ -149,10 +172,30 @@ public class SnarkManager implements Snark.CompleteListener {
_connectionAcceptor = new ConnectionAcceptor(_util);
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
_monitor.start();
// only if default instance
if ("i2psnark".equals(_contextName))
// delay until UpdateManager is there
_context.simpleScheduler().addEvent(new Register(), 4*60*1000);
// Not required, Jetty has a shutdown hook
//_context.addShutdownTask(new SnarkManagerShutdown());
}
/** @since 0.9.4 */
private class Register implements SimpleTimer.TimedEvent {
public void timeReached() {
if (!_running)
return;
_umgr = _context.updateManager();
if (_umgr != null) {
_uhandler = new UpdateHandler(_context, _umgr, SnarkManager.this);
_umgr.register(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT, 10);
_log.warn("Registering with update manager");
} else {
_log.warn("No update manager to register with");
}
}
}
/*
* Called by the webapp at Jetty shutdown.
* Stops all torrents. Does not close the tunnel, so the announces have a chance.
@@ -160,6 +203,10 @@ public class SnarkManager implements Snark.CompleteListener {
* Runs inline.
*/
public void stop() {
if (_umgr != null && _uhandler != null) {
//_uhandler.shutdown();
_umgr.unregister(_uhandler, UpdateType.ROUTER_SIGNED, UpdateMethod.TORRENT);
}
_running = false;
_monitor.interrupt();
_connectionAcceptor.halt();
@@ -200,11 +247,11 @@ public class SnarkManager implements Snark.CompleteListener {
* @since 0.8.9
*/
public boolean areFilesPublic() {
return Boolean.valueOf(_config.getProperty(PROP_FILES_PUBLIC)).booleanValue();
return Boolean.parseBoolean(_config.getProperty(PROP_FILES_PUBLIC));
}
public boolean shouldAutoStart() {
return Boolean.valueOf(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START)).booleanValue();
return Boolean.parseBoolean(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START));
}
/****
@@ -225,6 +272,18 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
/**
* For GUI
* @since 0.9.6
*/
public int getPageSize() {
try {
return Integer.parseInt(_config.getProperty(PROP_PAGE_SIZE));
} catch (NumberFormatException nfe) {
return DEFAULT_PAGE_SIZE;
}
}
private int getStartupDelayMinutes() {
try {
return Integer.parseInt(_config.getProperty(PROP_STARTUP_DELAY));
@@ -234,7 +293,7 @@ public class SnarkManager implements Snark.CompleteListener {
}
public File getDataDir() {
String dir = _config.getProperty(PROP_DIR, "i2psnark");
String dir = _config.getProperty(PROP_DIR, _contextName);
File f;
if (areFilesPublic())
f = new File(dir);
@@ -280,13 +339,15 @@ public class SnarkManager implements Snark.CompleteListener {
if (!_config.containsKey(PROP_UPLOADERS_TOTAL))
_config.setProperty(PROP_UPLOADERS_TOTAL, "" + Snark.MAX_TOTAL_UPLOADERS);
if (!_config.containsKey(PROP_DIR))
_config.setProperty(PROP_DIR, "i2psnark");
_config.setProperty(PROP_DIR, _contextName);
if (!_config.containsKey(PROP_AUTO_START))
_config.setProperty(PROP_AUTO_START, DEFAULT_AUTO_START);
if (!_config.containsKey(PROP_REFRESH_DELAY))
_config.setProperty(PROP_REFRESH_DELAY, Integer.toString(DEFAULT_REFRESH_DELAY_SECS));
if (!_config.containsKey(PROP_STARTUP_DELAY))
_config.setProperty(PROP_STARTUP_DELAY, Integer.toString(DEFAULT_STARTUP_DELAY));
if (!_config.containsKey(PROP_PAGE_SIZE))
_config.setProperty(PROP_PAGE_SIZE, Integer.toString(DEFAULT_PAGE_SIZE));
if (!_config.containsKey(PROP_THEME))
_config.setProperty(PROP_THEME, DEFAULT_THEME);
// no, so we can switch default to true later
@@ -384,11 +445,11 @@ public class SnarkManager implements Snark.CompleteListener {
if (ot != null)
_util.setOpenTrackers(getOpenTrackers());
String useOT = _config.getProperty(PROP_USE_OPENTRACKERS);
boolean bOT = useOT == null || Boolean.valueOf(useOT).booleanValue();
boolean bOT = useOT == null || Boolean.parseBoolean(useOT);
_util.setUseOpenTrackers(bOT);
// careful, so we can switch default to true later
_util.setUseDHT(Boolean.valueOf(_config.getProperty(PROP_USE_DHT,
Boolean.toString(I2PSnarkUtil.DEFAULT_USE_DHT))).booleanValue());
_util.setUseDHT(Boolean.parseBoolean(_config.getProperty(PROP_USE_DHT,
Boolean.toString(I2PSnarkUtil.DEFAULT_USE_DHT))));
getDataDir().mkdirs();
initTrackerMap();
}
@@ -404,11 +465,15 @@ public class SnarkManager implements Snark.CompleteListener {
return defaultVal;
}
/**
* all params may be null or need trimming
*/
public void updateConfig(String dataDir, boolean filesPublic, boolean autoStart, String refreshDelay,
String startDelay, String seedPct, String eepHost,
String startDelay, String pageSize, String seedPct, String eepHost,
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
String upLimit, String upBW, boolean useOpenTrackers, boolean useDHT, String theme) {
boolean changed = false;
boolean interruptMonitor = false;
//if (eepHost != null) {
// // unused, we use socket eepget
// int port = _util.getEepProxyPort();
@@ -425,12 +490,12 @@ public class SnarkManager implements Snark.CompleteListener {
//}
if (upLimit != null) {
int limit = _util.getMaxUploaders();
try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {}
try { limit = Integer.parseInt(upLimit.trim()); } catch (NumberFormatException nfe) {}
if ( limit != _util.getMaxUploaders()) {
if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) {
_util.setMaxUploaders(limit);
changed = true;
_config.setProperty(PROP_UPLOADERS_TOTAL, "" + limit);
_config.setProperty(PROP_UPLOADERS_TOTAL, Integer.toString(limit));
addMessage(_("Total uploaders limit changed to {0}", limit));
} else {
addMessage(_("Minimum total uploaders limit is {0}", Snark.MIN_TOTAL_UPLOADERS));
@@ -439,12 +504,12 @@ public class SnarkManager implements Snark.CompleteListener {
}
if (upBW != null) {
int limit = _util.getMaxUpBW();
try { limit = Integer.parseInt(upBW); } catch (NumberFormatException nfe) {}
try { limit = Integer.parseInt(upBW.trim()); } catch (NumberFormatException nfe) {}
if ( limit != _util.getMaxUpBW()) {
if ( limit >= MIN_UP_BW ) {
_util.setMaxUpBW(limit);
changed = true;
_config.setProperty(PROP_UPBW_MAX, "" + limit);
_config.setProperty(PROP_UPBW_MAX, Integer.toString(limit));
addMessage(_("Up BW limit changed to {0}KBps", limit));
} else {
addMessage(_("Minimum up bandwidth limit is {0}KBps", MIN_UP_BW));
@@ -454,21 +519,21 @@ public class SnarkManager implements Snark.CompleteListener {
if (startDelay != null){
int minutes = _util.getStartupDelay();
try { minutes = Integer.parseInt(startDelay); } catch (NumberFormatException nfe) {}
try { minutes = Integer.parseInt(startDelay.trim()); } catch (NumberFormatException nfe) {}
if ( minutes != _util.getStartupDelay()) {
_util.setStartupDelay(minutes);
changed = true;
_config.setProperty(PROP_STARTUP_DELAY, "" + minutes);
_config.setProperty(PROP_STARTUP_DELAY, Integer.toString(minutes));
addMessage(_("Startup delay changed to {0}", DataHelper.formatDuration2(minutes * 60 * 1000)));
}
}
if (refreshDelay != null) {
try {
int secs = Integer.parseInt(refreshDelay);
int secs = Integer.parseInt(refreshDelay.trim());
if (secs != getRefreshDelaySeconds()) {
changed = true;
_config.setProperty(PROP_REFRESH_DELAY, refreshDelay);
_config.setProperty(PROP_REFRESH_DELAY, Integer.toString(secs));
if (secs >= 0)
addMessage(_("Refresh time changed to {0}", DataHelper.formatDuration2(secs * 1000)));
else
@@ -477,6 +542,42 @@ public class SnarkManager implements Snark.CompleteListener {
} catch (NumberFormatException nfe) {}
}
if (pageSize != null) {
try {
int size = Integer.parseInt(pageSize.trim());
if (size <= 0)
size = 999999;
else if (size < 5)
size = 5;
if (size != getPageSize()) {
changed = true;
pageSize = Integer.toString(size);
_config.setProperty(PROP_PAGE_SIZE, pageSize);
addMessage(_("Page size changed to {0}", pageSize));
}
} catch (NumberFormatException nfe) {}
}
if (dataDir != null && !dataDir.equals(getDataDir().getAbsolutePath())) {
dataDir = dataDir.trim();
File dd = new File(dataDir);
if (!dd.isAbsolute()) {
addMessage(_("Data directory must be an absolute path") + ": " + dataDir);
} else if (!dd.exists()) {
addMessage(_("Data directory does not exist") + ": " + dataDir);
} else if (!dd.isDirectory()) {
addMessage(_("Not a directory") + ": " + dataDir);
} else if (!dd.canRead()) {
addMessage(_("Unreadable") + ": " + dataDir);
} else {
changed = true;
interruptMonitor = true;
_config.setProperty(PROP_DIR, dataDir);
addMessage(_("Data directory changed to {0}", dataDir));
}
}
// Start of I2CP stuff.
// i2cpHost will generally be null since it is hidden from the form if in router context.
@@ -611,6 +712,9 @@ public class SnarkManager implements Snark.CompleteListener {
}
if (changed) {
saveConfig();
if (interruptMonitor)
// Data dir changed. this will stop and remove all old torrents, and add the new ones
_monitor.interrupt();
} else {
addMessage(_("Configuration unchanged."));
}
@@ -706,8 +810,13 @@ public class SnarkManager implements Snark.CompleteListener {
public Properties getConfig() { return _config; }
/** @since Jetty 7 */
public String getConfigFilename() {
return _configFile.getAbsolutePath();
}
/** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */
private static final int MAX_FILES_PER_TORRENT = 512;
public static final int MAX_FILES_PER_TORRENT = 512;
/**
* Set of canonical .torrent filenames that we are dealing with.
@@ -723,6 +832,14 @@ public class SnarkManager implements Snark.CompleteListener {
*/
public Snark getTorrent(String filename) { synchronized (_snarks) { return _snarks.get(filename); } }
/**
* Unmodifiable
* @since 0.9.4
*/
public Collection<Snark> getTorrents() {
return Collections.unmodifiableCollection(_snarks.values());
}
/**
* Grab the torrent given the base name of the storage
* @return Snark or null
@@ -853,7 +970,9 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
} catch (IOException ioe) {
addMessage(_("Torrent in \"{0}\" is invalid", sfile.getName()) + ": " + ioe.getMessage());
String err = _("Torrent in \"{0}\" is invalid", sfile.getName()) + ": " + ioe.getMessage();
addMessage(err);
_log.error(err, ioe);
if (sfile.exists())
sfile.delete();
return;
@@ -889,7 +1008,27 @@ public class SnarkManager implements Snark.CompleteListener {
* @since 0.8.4
*/
public void addMagnet(String name, byte[] ih, String trackerURL, boolean updateStatus) {
Snark torrent = new Snark(_util, name, ih, trackerURL, this,
addMagnet(name, ih, trackerURL, updateStatus, shouldAutoStart(), this);
}
/**
* Add a torrent with the info hash alone (magnet / maggot)
* External use is for UpdateRunner.
*
* @param name hex or b32 name from the magnet link
* @param ih 20 byte info hash
* @param trackerURL may be null
* @param updateStatus should we add this magnet to the config file,
* to save it across restarts, in case we don't get
* the metadata before shutdown?
* @param listener to intercept callbacks, should pass through to this
* @return the new Snark or null on failure
* @throws RuntimeException via Snark.fatal()
* @since 0.9.4
*/
public Snark addMagnet(String name, byte[] ih, String trackerURL, boolean updateStatus,
boolean autoStart, CompleteListener listener) {
Snark torrent = new Snark(_util, name, ih, trackerURL, listener,
_peerCoordinatorSet, _connectionAcceptor,
false, getDataDir().getPath());
@@ -897,7 +1036,7 @@ public class SnarkManager implements Snark.CompleteListener {
Snark snark = getTorrentByInfoHash(ih);
if (snark != null) {
addMessage(_("Torrent with this info hash is already running: {0}", snark.getBaseName()));
return;
return null;
}
// Tell the dir monitor not to delete us
_magnets.add(name);
@@ -905,8 +1044,8 @@ public class SnarkManager implements Snark.CompleteListener {
saveMagnetStatus(ih);
_snarks.put(name, torrent);
}
if (shouldAutoStart()) {
torrent.startTorrent();
if (autoStart) {
startTorrent(ih);
addMessage(_("Fetching {0}", name));
DHT dht = _util.getDHT();
boolean shouldWarn = _util.connected() &&
@@ -918,7 +1057,8 @@ public class SnarkManager implements Snark.CompleteListener {
}
} else {
addMessage(_("Adding {0}", name));
}
}
return torrent;
}
/**
@@ -1370,6 +1510,8 @@ public class SnarkManager implements Snark.CompleteListener {
} catch (Exception e) {
_log.error("Error in the DirectoryMonitor", e);
}
if (!_snarks.isEmpty())
addMessage(_("Up bandwidth limit is {0} KBps", _util.getMaxUpBW()));
}
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
}
@@ -1387,7 +1529,7 @@ public class SnarkManager implements Snark.CompleteListener {
if (meta == null || storage == null)
return;
StringBuilder buf = new StringBuilder(256);
buf.append("<a href=\"/i2psnark/").append(storage.getBaseName());
buf.append("<a href=\"").append(_contextPath).append('/').append(storage.getBaseName());
if (meta.getFiles() != null)
buf.append('/');
buf.append("\">").append(storage.getBaseName()).append("</a>");
@@ -1469,6 +1611,12 @@ public class SnarkManager implements Snark.CompleteListener {
addMessage(message);
}
/**
* A Snark.CompleteListener method.
* @since 0.9.4
*/
public void gotPiece(Snark snark) {}
// End Snark.CompleteListeners
/**

View File

@@ -21,6 +21,7 @@
package org.klomp.snark;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
@@ -32,17 +33,23 @@ import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.I2PAppContext;
import net.i2p.crypto.SHA1;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
import net.i2p.util.ByteCache;
import net.i2p.util.Log;
import net.i2p.util.SecureFile;
import net.i2p.util.SystemVersion;
/**
* Maintains pieces on disk. Can be used to store and retrieve pieces.
*/
public class Storage
{
private MetaInfo metainfo;
private final MetaInfo metainfo;
private long[] lengths;
private RandomAccessFile[] rafs;
private String[] names;
@@ -66,9 +73,11 @@ public class Storage
private final int pieces;
private final long total_length;
private boolean changed;
private volatile boolean _isChecking;
private final AtomicInteger _allocateCount = new AtomicInteger();
/** The default piece size. */
private static final int MIN_PIECE_SIZE = 256*1024;
private static final int DEFAULT_PIECE_SIZE = 256*1024;
/** note that we start reducing max number of peer connections above 1MB */
public static final int MAX_PIECE_SIZE = 2*1024*1024;
/** The maximum number of pieces in a torrent. */
@@ -77,23 +86,24 @@ public class Storage
private static final Map<String, String> _filterNameCache = new ConcurrentHashMap();
private static final boolean _isWindows = System.getProperty("os.name").startsWith("Win");
private static final boolean _isWindows = SystemVersion.isWindows();
private static final int BUFSIZE = PeerState.PARTSIZE;
private static final ByteCache _cache = ByteCache.getInstance(16, BUFSIZE);
/**
* Creates a new storage based on the supplied MetaInfo. This will
* try to create and/or check all needed files in the MetaInfo.
*
* @exception IOException when creating and/or checking files fails.
* Does not check storage. Caller MUST call check()
*/
public Storage(I2PSnarkUtil util, MetaInfo metainfo, StorageListener listener)
throws IOException
{
_util = util;
_log = util.getContext().logManager().getLog(Storage.class);
this.metainfo = metainfo;
this.listener = listener;
needed = metainfo.getPieces();
_probablyComplete = false;
bitfield = new BitField(needed);
piece_size = metainfo.getPieceLength(0);
pieces = needed;
@@ -101,14 +111,18 @@ public class Storage
}
/**
* Creates a storage from the existing file or directory together
* with an appropriate MetaInfo file as can be announced on the
* given announce String location.
* Creates a storage from the existing file or directory.
* Creates an in-memory metainfo but does not save it to
* a file, caller must do that.
*
* Creates the metainfo, this may take a LONG time. BLOCKING.
*
* @param announce may be null
* @param listener may be null
* @throws IOException when creating and/or checking files fails.
*/
public Storage(I2PSnarkUtil util, File baseFile, String announce,
List<List<String>> announce_list,
boolean privateTorrent, StorageListener listener)
throws IOException
{
@@ -129,10 +143,18 @@ public class Storage
if (total <= 0)
throw new IOException("Torrent contains no data");
if (total > MAX_TOTAL_SIZE)
throw new IOException("Torrent too big (" + total + " bytes), max is " + MAX_TOTAL_SIZE);
int pc_size = MIN_PIECE_SIZE;
int pc_size;
if (total <= 5*1024*1024)
pc_size = DEFAULT_PIECE_SIZE / 4;
else if (total <= 10*1024*1024)
pc_size = DEFAULT_PIECE_SIZE / 2;
else
pc_size = DEFAULT_PIECE_SIZE;
int pcs = (int) ((total - 1)/pc_size) + 1;
while (pcs > MAX_PIECES && pc_size < MAX_PIECE_SIZE)
while (pcs > (MAX_PIECES * 2 / 3) && pc_size < MAX_PIECE_SIZE)
{
pc_size *= 2;
pcs = (int) ((total - 1)/pc_size) +1;
@@ -164,9 +186,11 @@ public class Storage
lengthsList = null;
}
// TODO thread this so we can return and show something on the UI
byte[] piece_hashes = fast_digestCreate();
metainfo = new MetaInfo(announce, baseFile.getName(), null, files,
lengthsList, piece_size, piece_hashes, total, privateTorrent);
lengthsList, piece_size, piece_hashes, total, privateTorrent,
announce_list);
}
@@ -199,6 +223,8 @@ public class Storage
private void getFiles(File base) throws IOException
{
if (base.getAbsolutePath().equals("/"))
throw new IOException("Don't seed root");
ArrayList files = new ArrayList();
addFiles(files, base);
@@ -227,12 +253,15 @@ public class Storage
}
}
private void addFiles(List l, File f)
{
if (!f.isDirectory())
l.add(f);
else
{
/**
* @throws IOException if too many total files
*/
private void addFiles(List l, File f) throws IOException {
if (!f.isDirectory()) {
if (l.size() >= SnarkManager.MAX_FILES_PER_TORRENT)
throw new IOException("Too many files, limit is " + SnarkManager.MAX_FILES_PER_TORRENT + ", zip them?");
l.add(f);
} else {
File[] files = f.listFiles();
if (files == null)
{
@@ -278,6 +307,23 @@ public class Storage
return changed;
}
/**
* File checking in progress.
* @since 0.9.3
*/
public boolean isChecking() {
return _isChecking;
}
/**
* Disk allocation (ballooning) in progress.
* Always false on Windows.
* @since 0.9.3
*/
public boolean isAllocating() {
return _allocateCount.get() > 0;
}
/**
* @param file canonical path (non-directory)
* @return number of bytes remaining; -1 if unknown file
@@ -697,11 +743,25 @@ public class Storage
* This is called at the beginning, and at presumed completion,
* so we have to be careful about locking.
*
* TODO thread the checking so we can return and display
* something on the UI
*
* @param recheck if true, this is a check after we downloaded the
* last piece, and we don't modify the global bitfield unless
* the check fails.
*/
private void checkCreateFiles(boolean recheck) throws IOException
private void checkCreateFiles(boolean recheck) throws IOException {
synchronized(this) {
_isChecking = true;
try {
locked_checkCreateFiles(recheck);
} finally {
_isChecking = false;
}
}
}
private void locked_checkCreateFiles(boolean recheck) throws IOException
{
// Whether we are resuming or not,
// if any of the files already exists we assume we are resuming.
@@ -861,10 +921,19 @@ public class Storage
final int ZEROBLOCKSIZE = (int) Math.min(remaining, 32*1024);
byte[] zeros = new byte[ZEROBLOCKSIZE];
rafs[nr].seek(0);
while (remaining > 0) {
int size = (int) Math.min(remaining, ZEROBLOCKSIZE);
rafs[nr].write(zeros, 0, size);
remaining -= size;
// don't bother setting flag for small files
if (remaining > 20*1024*1024)
_allocateCount.incrementAndGet();
try {
while (remaining > 0) {
int size = (int) Math.min(remaining, ZEROBLOCKSIZE);
rafs[nr].write(zeros, 0, size);
remaining -= size;
}
} finally {
remaining = lengths[nr];
if (remaining > 20*1024*1024)
_allocateCount.decrementAndGet();
}
isSparse[nr] = false;
}
@@ -898,26 +967,34 @@ public class Storage
* Returns a byte array containing a portion of the requested piece or null if
* the storage doesn't contain the piece yet.
*/
public byte[] getPiece(int piece, int off, int len) throws IOException
public ByteArray getPiece(int piece, int off, int len) throws IOException
{
if (!bitfield.get(piece))
return null;
//Catch a common place for OOMs esp. on 1MB pieces
ByteArray rv;
byte[] bs;
try {
bs = new byte[len];
// Will be restored to cache in Message.sendMessage()
if (len == BUFSIZE)
rv = _cache.acquire();
else
rv = new ByteArray(new byte[len]);
} catch (OutOfMemoryError oom) {
if (_log.shouldLog(Log.WARN))
_log.warn("Out of memory, can't honor request for piece " + piece, oom);
return null;
}
bs = rv.getData();
getUncheckedPiece(piece, bs, off, len);
return bs;
return rv;
}
/**
* Put the piece in the Storage if it is correct.
* Warning - takes a LONG time if complete as it does the recheck here.
* TODO thread the recheck?
*
* @return true if the piece was correct (sha metainfo hash
* matches), otherwise false.
@@ -935,9 +1012,9 @@ public class Storage
// TODO alternative - check hash on the fly as we write to the file,
// to save another I/O pass
boolean correctHash = metainfo.checkPiece(pp);
if (listener != null)
listener.storageChecked(this, piece, correctHash);
if (!correctHash) {
if (listener != null)
listener.storageChecked(this, piece, false);
return false;
}
@@ -999,6 +1076,9 @@ public class Storage
complete = needed == 0;
}
}
// tell listener after counts are updated
if (listener != null)
listener.storageChecked(this, piece, true);
if (complete) {
// do we also need to close all of the files and reopen
@@ -1136,4 +1216,43 @@ public class Storage
rafs[i] = null;
}
/**
* Create a metainfo.
* Used in the installer build process; do not comment out.
* @since 0.9.4
*/
public static void main(String[] args) {
if (args.length < 1 || args.length > 2) {
System.err.println("Usage: Storage file-or-dir [announceURL]");
System.exit(1);
}
File base = new File(args[0]);
String announce = args.length == 2 ? args[1] : null;
I2PAppContext ctx = I2PAppContext.getGlobalContext();
I2PSnarkUtil util = new I2PSnarkUtil(ctx);
File file = null;
FileOutputStream out = null;
try {
Storage storage = new Storage(util, base, announce, null, false, null);
MetaInfo meta = storage.getMetaInfo();
file = new File(storage.getBaseName() + ".torrent");
out = new FileOutputStream(file);
out.write(meta.getTorrentData());
String hex = DataHelper.toString(meta.getInfoHash());
System.out.println("Created: " + file);
System.out.println("InfoHash: " + hex);
String basename = base.getName().replace(" ", "%20");
String magnet = MagnetURI.MAGNET_FULL + hex + "&dn=" + basename;
if (announce != null)
magnet += "&tr=" + announce;
System.out.println("Magnet: " + magnet);
} catch (IOException ioe) {
if (file != null)
file.delete();
ioe.printStackTrace();
System.exit(1);
} finally {
try { if (out != null) out.close(); } catch (IOException ioe) {}
}
}
}

View File

@@ -20,6 +20,7 @@
package org.klomp.snark;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -30,6 +31,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
@@ -39,10 +41,12 @@ import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.util.ConvertToHash;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer2;
import org.klomp.snark.bencode.InvalidBEncodingException;
import org.klomp.snark.dht.DHT;
/**
@@ -70,6 +74,8 @@ public class TrackerClient implements Runnable {
private static final String COMPLETED_EVENT = "completed";
private static final String STOPPED_EVENT = "stopped";
private static final String NOT_REGISTERED = "torrent not registered"; //bytemonsoon
/** this is our equivalent to router.utorrent.com for bootstrap */
private static final String DEFAULT_BACKUP_TRACKER = "http://tracker.welterde.i2p/a";
private final static int SLEEP = 5; // 5 minutes.
private final static int DELAY_MIN = 2000; // 2 secs.
@@ -78,7 +84,7 @@ public class TrackerClient implements Runnable {
private final static int INITIAL_SLEEP = 90*1000;
private final static int MAX_CONSEC_FAILS = 5; // slow down after this
private final static int LONG_SLEEP = 30*60*1000; // sleep a while after lots of fails
private final static long MIN_TRACKER_ANNOUNCE_INTERVAL = 10*60*1000;
private final static long MIN_TRACKER_ANNOUNCE_INTERVAL = 15*60*1000;
private final static long MIN_DHT_ANNOUNCE_INTERVAL = 10*60*1000;
private final I2PSnarkUtil _util;
@@ -105,7 +111,8 @@ public class TrackerClient implements Runnable {
private boolean completed;
private volatile boolean _fastUnannounce;
private long lastDHTAnnounce;
private final List<Tracker> trackers;
private final List<TCTracker> trackers;
private final List<TCTracker> backupTrackers;
/**
* Call start() to start it.
@@ -131,6 +138,7 @@ public class TrackerClient implements Runnable {
this.infoHash = urlencode(snark.getInfoHash());
this.peerID = urlencode(snark.getID());
this.trackers = new ArrayList(2);
this.backupTrackers = new ArrayList(2);
}
public synchronized void start() {
@@ -233,7 +241,7 @@ public class TrackerClient implements Runnable {
if (!_initialized) {
_initialized = true;
// FIXME only when starting everybody at once, not for a single torrent
long delay = I2PAppContext.getGlobalContext().random().nextInt(30*1000);
long delay = _util.getContext().random().nextInt(30*1000);
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {}
@@ -264,49 +272,90 @@ public class TrackerClient implements Runnable {
primary = meta.getAnnounce();
else if (additionalTrackerURL != null)
primary = additionalTrackerURL;
Set<Hash> trackerHashes = new HashSet(8);
// primary tracker
if (primary != null) {
if (isValidAnnounce(primary)) {
trackers.add(new Tracker(primary, true));
_log.debug("Announce: [" + primary + "] infoHash: " + infoHash);
if (isNewValidTracker(trackerHashes, primary)) {
trackers.add(new TCTracker(primary, true));
if (_log.shouldLog(Log.DEBUG))
_log.debug("Announce: [" + primary + "] infoHash: " + infoHash);
} else {
_log.warn("Skipping invalid or non-i2p announce: " + primary);
if (_log.shouldLog(Log.WARN))
_log.warn("Skipping invalid or non-i2p announce: " + primary);
}
} else {
_log.warn("No primary announce");
primary = "";
}
List tlist = _util.getOpenTrackers();
if (tlist != null && (meta == null || !meta.isPrivate())) {
// announce list
if (meta != null && !meta.isPrivate()) {
List<List<String>> list = meta.getAnnounceList();
if (list != null) {
for (List<String> llist : list) {
for (String url : llist) {
if (!isNewValidTracker(trackerHashes, url))
continue;
trackers.add(new TCTracker(url, trackers.isEmpty()));
if (_log.shouldLog(Log.DEBUG))
_log.debug("Additional announce (list): [" + url + "] for infoHash: " + infoHash);
}
}
}
}
// configured open trackers
if (meta == null || !meta.isPrivate()) {
List<String> tlist = _util.getOpenTrackers();
for (int i = 0; i < tlist.size(); i++) {
String url = (String)tlist.get(i);
if (!isValidAnnounce(url)) {
_log.error("Bad announce URL: [" + url + "]");
String url = tlist.get(i);
if (!isNewValidTracker(trackerHashes, url))
continue;
}
int slash = url.indexOf('/', 7);
if (slash <= 7) {
_log.error("Bad announce URL: [" + url + "]");
// opentrackers are primary if we don't have primary
trackers.add(new TCTracker(url, trackers.isEmpty()));
if (_log.shouldLog(Log.DEBUG))
_log.debug("Additional announce: [" + url + "] for infoHash: " + infoHash);
}
}
// backup trackers if DHT needs bootstrapping
if (trackers.isEmpty() && (meta == null || !meta.isPrivate())) {
List<String> tlist = _util.getBackupTrackers();
for (int i = 0; i < tlist.size(); i++) {
String url = tlist.get(i);
if (!isNewValidTracker(trackerHashes, url))
continue;
}
if (primary.startsWith(url.substring(0, slash)))
continue;
String dest = _util.lookup(url.substring(7, slash));
if (dest == null) {
_log.error("Announce host unknown: [" + url.substring(7, slash) + "]");
continue;
}
if (primary.startsWith("http://" + dest))
continue;
if (primary.startsWith("http://i2p/" + dest))
continue;
// opentrackers are primary if we don't have primary
trackers.add(new Tracker(url, primary.equals("")));
_log.debug("Additional announce: [" + url + "] for infoHash: " + infoHash);
backupTrackers.add(new TCTracker(url, false));
if (_log.shouldLog(Log.DEBUG))
_log.debug("Backup announce: [" + url + "] for infoHash: " + infoHash);
}
if (backupTrackers.isEmpty()) {
backupTrackers.add(new TCTracker(DEFAULT_BACKUP_TRACKER, false));
}
}
this.completed = coordinator.getLeft() == 0;
}
/**
* @param existing the ones we already know about
* @param ann an announce URL non-null
* @return true if ann is valid and new; adds to existing if returns true
* @since 0.9.5
*/
private boolean isNewValidTracker(Set<Hash> existing, String ann) {
Hash h = getHostHash(ann);
if (h == null) {
_log.error("Bad announce URL: [" + ann + ']');
return false;
}
boolean rv = existing.add(h);
if (!rv) {
if (_log.shouldLog(Log.INFO))
_log.info("Dup announce URL: [" + ann + ']');
}
return rv;
}
/**
* Announce to all the trackers, get peers from PEX and DHT, then queue up a SimpleTimer2 event.
* This will take several seconds to several minutes.
@@ -315,7 +364,7 @@ public class TrackerClient implements Runnable {
private void loop() {
try
{
Random r = I2PAppContext.getGlobalContext().random();
// normally this will only go once, then call queueLoop() and return
while(!stop)
{
if (!verifyConnected()) {
@@ -325,187 +374,25 @@ public class TrackerClient implements Runnable {
// Local DHT tracker announce
DHT dht = _util.getDHT();
if (dht != null)
if (dht != null && (meta == null || !meta.isPrivate()))
dht.announce(snark.getInfoHash());
long uploaded = coordinator.getUploaded();
long downloaded = coordinator.getDownloaded();
long left = coordinator.getLeft(); // -1 in magnet mode
// First time we got a complete download?
String event;
if (!completed && left == 0)
{
completed = true;
event = COMPLETED_EVENT;
}
else
event = NO_EVENT;
// *** loop once for each tracker
int maxSeenPeers = 0;
for (Tracker tr : trackers) {
if ((!stop) && (!tr.stop) &&
(completed || coordinator.needOutboundPeers() || !tr.started) &&
(event.equals(COMPLETED_EVENT) || System.currentTimeMillis() > tr.lastRequestTime + tr.interval))
{
try
{
if (!tr.started)
event = STARTED_EVENT;
TrackerInfo info = doRequest(tr, infoHash, peerID,
uploaded, downloaded, left,
event);
snark.setTrackerProblems(null);
tr.trackerProblems = null;
tr.registerFails = 0;
tr.consecutiveFails = 0;
if (tr.isPrimary)
consecutiveFails = 0;
runStarted = true;
tr.started = true;
Set<Peer> peers = info.getPeers();
tr.seenPeers = info.getPeerCount();
if (snark.getTrackerSeenPeers() < tr.seenPeers) // update rising number quickly
snark.setTrackerSeenPeers(tr.seenPeers);
// pass everybody over to our tracker
dht = _util.getDHT();
if (dht != null) {
for (Peer peer : peers) {
dht.announce(snark.getInfoHash(), peer.getPeerID().getDestHash());
}
}
if (coordinator.needOutboundPeers()) {
// we only want to talk to new people if we need things
// from them (duh)
List<Peer> ordered = new ArrayList(peers);
Collections.shuffle(ordered, r);
Iterator<Peer> it = ordered.iterator();
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
Peer cur = it.next();
// FIXME if id == us || dest == us continue;
// only delay if we actually make an attempt to add peer
if(coordinator.addPeer(cur) && it.hasNext()) {
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
}
}
catch (IOException ioe)
{
// Probably not fatal (if it doesn't last to long...)
if (_log.shouldLog(Log.WARN))
_log.warn
("WARNING: Could not contact tracker at '"
+ tr.announce + "': " + ioe);
tr.trackerProblems = ioe.getMessage();
// don't show secondary tracker problems to the user
if (tr.isPrimary)
snark.setTrackerProblems(tr.trackerProblems);
if (tr.trackerProblems.toLowerCase(Locale.US).startsWith(NOT_REGISTERED)) {
// Give a guy some time to register it if using opentrackers too
if (trackers.size() == 1) {
stop = true;
snark.stopTorrent();
} else { // hopefully each on the opentrackers list is really open
if (tr.registerFails++ > MAX_REGISTER_FAILS)
tr.stop = true;
}
}
if (++tr.consecutiveFails == MAX_CONSEC_FAILS) {
tr.seenPeers = 0;
if (tr.interval < LONG_SLEEP)
tr.interval = LONG_SLEEP; // slow down
}
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Not announcing to " + tr.announce + " last announce was " +
new Date(tr.lastRequestTime) + " interval is " + DataHelper.formatDuration(tr.interval));
}
if ((!tr.stop) && maxSeenPeers < tr.seenPeers)
maxSeenPeers = tr.seenPeers;
} // *** end of trackers loop here
// Get peers from PEX
if (coordinator.needOutboundPeers() && (meta == null || !meta.isPrivate()) && !stop) {
Set<PeerID> pids = coordinator.getPEXPeers();
if (!pids.isEmpty()) {
if (_log.shouldLog(Log.INFO))
_log.info("Got " + pids.size() + " from PEX");
List<Peer> peers = new ArrayList(pids.size());
for (PeerID pID : pids) {
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
}
Collections.shuffle(peers, r);
Iterator<Peer> it = peers.iterator();
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
Peer cur = it.next();
if (coordinator.addPeer(cur) && it.hasNext()) {
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Not getting PEX peers");
if (!trackers.isEmpty())
maxSeenPeers = getPeersFromTrackers(trackers);
int p = getPeersFromPEX();
if (p > maxSeenPeers)
maxSeenPeers = p;
p = getPeersFromDHT();
if (p > maxSeenPeers)
maxSeenPeers = p;
// backup if DHT needs bootstrapping
if (trackers.isEmpty() && !backupTrackers.isEmpty() && dht != null && dht.size() < 16) {
p = getPeersFromTrackers(backupTrackers);
if (p > maxSeenPeers)
maxSeenPeers = p;
}
// Get peers from DHT
// FIXME this needs to be in its own thread
dht = _util.getDHT();
if (dht != null && (meta == null || !meta.isPrivate()) && (!stop) &&
_util.getContext().clock().now() > lastDHTAnnounce + MIN_DHT_ANNOUNCE_INTERVAL) {
int numwant;
if (event.equals(STOPPED_EVENT) || !coordinator.needOutboundPeers())
numwant = 1;
else
numwant = _util.getMaxConnections();
Collection<Hash> hashes = dht.getPeers(snark.getInfoHash(), numwant, 2*60*1000);
if (!hashes.isEmpty()) {
runStarted = true;
lastDHTAnnounce = _util.getContext().clock().now();
}
if (_log.shouldLog(Log.INFO))
_log.info("Got " + hashes + " from DHT");
// announce ourselves while the token is still good
// FIXME this needs to be in its own thread
if (!stop) {
// announce only to the 1 closest
int good = dht.announce(snark.getInfoHash(), 1, 5*60*1000);
if (_log.shouldLog(Log.INFO))
_log.info("Sent " + good + " good announces to DHT");
}
// now try these peers
if ((!stop) && !hashes.isEmpty()) {
List<Peer> peers = new ArrayList(hashes.size());
for (Hash h : hashes) {
PeerID pID = new PeerID(h.getData(), _util);
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
}
Collections.shuffle(peers, r);
Iterator<Peer> it = peers.iterator();
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
Peer cur = it.next();
if (coordinator.addPeer(cur) && it.hasNext()) {
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Not getting DHT peers");
}
// we could try and total the unique peers but that's too hard for now
snark.setTrackerSeenPeers(maxSeenPeers);
@@ -516,6 +403,7 @@ public class TrackerClient implements Runnable {
// Sleep some minutes...
// Sleep the minimum interval for all the trackers, but 60s minimum
int delay;
Random r = _util.getContext().random();
int random = r.nextInt(120*1000);
if (completed && runStarted)
delay = 3*SLEEP*60*1000 + random;
@@ -547,6 +435,219 @@ public class TrackerClient implements Runnable {
}
}
/**
* @return max peers seen
*/
private int getPeersFromTrackers(List<TCTracker> trckrs) {
long left = coordinator.getLeft(); // -1 in magnet mode
// First time we got a complete download?
boolean newlyCompleted;
if (!completed && left == 0) {
completed = true;
newlyCompleted = true;
} else {
newlyCompleted = false;
}
// *** loop once for each tracker
int maxSeenPeers = 0;
for (TCTracker tr : trckrs) {
if ((!stop) && (!tr.stop) &&
(completed || coordinator.needOutboundPeers() || !tr.started) &&
(newlyCompleted || System.currentTimeMillis() > tr.lastRequestTime + tr.interval))
{
try
{
long uploaded = coordinator.getUploaded();
long downloaded = coordinator.getDownloaded();
left = coordinator.getLeft();
String event;
if (!tr.started) {
event = STARTED_EVENT;
} else if (newlyCompleted) {
event = COMPLETED_EVENT;
} else {
event = NO_EVENT;
}
TrackerInfo info = doRequest(tr, infoHash, peerID,
uploaded, downloaded, left,
event);
snark.setTrackerProblems(null);
tr.trackerProblems = null;
tr.registerFails = 0;
tr.consecutiveFails = 0;
if (tr.isPrimary)
consecutiveFails = 0;
runStarted = true;
tr.started = true;
Set<Peer> peers = info.getPeers();
tr.seenPeers = info.getPeerCount();
if (snark.getTrackerSeenPeers() < tr.seenPeers) // update rising number quickly
snark.setTrackerSeenPeers(tr.seenPeers);
// pass everybody over to our tracker
DHT dht = _util.getDHT();
if (dht != null) {
for (Peer peer : peers) {
dht.announce(snark.getInfoHash(), peer.getPeerID().getDestHash());
}
}
if (coordinator.needOutboundPeers()) {
// we only want to talk to new people if we need things
// from them (duh)
List<Peer> ordered = new ArrayList(peers);
Random r = _util.getContext().random();
Collections.shuffle(ordered, r);
Iterator<Peer> it = ordered.iterator();
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
Peer cur = it.next();
// FIXME if id == us || dest == us continue;
// only delay if we actually make an attempt to add peer
if(coordinator.addPeer(cur) && it.hasNext()) {
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
}
}
catch (IOException ioe)
{
// Probably not fatal (if it doesn't last to long...)
if (_log.shouldLog(Log.WARN))
_log.warn
("WARNING: Could not contact tracker at '"
+ tr.announce + "': " + ioe);
tr.trackerProblems = ioe.getMessage();
// don't show secondary tracker problems to the user
if (tr.isPrimary)
snark.setTrackerProblems(tr.trackerProblems);
if (tr.trackerProblems.toLowerCase(Locale.US).startsWith(NOT_REGISTERED)) {
// Give a guy some time to register it if using opentrackers too
//if (trckrs.size() == 1) {
// stop = true;
// snark.stopTorrent();
//} else { // hopefully each on the opentrackers list is really open
if (tr.registerFails++ > MAX_REGISTER_FAILS)
tr.stop = true;
//
}
if (++tr.consecutiveFails == MAX_CONSEC_FAILS) {
tr.seenPeers = 0;
if (tr.interval < LONG_SLEEP)
tr.interval = LONG_SLEEP; // slow down
}
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Not announcing to " + tr.announce + " last announce was " +
new Date(tr.lastRequestTime) + " interval is " + DataHelper.formatDuration(tr.interval));
}
if ((!tr.stop) && maxSeenPeers < tr.seenPeers)
maxSeenPeers = tr.seenPeers;
} // *** end of trackers loop here
return maxSeenPeers;
}
/**
* @return max peers seen
*/
private int getPeersFromPEX() {
// Get peers from PEX
int rv = 0;
if (coordinator.needOutboundPeers() && (meta == null || !meta.isPrivate()) && !stop) {
Set<PeerID> pids = coordinator.getPEXPeers();
if (!pids.isEmpty()) {
if (_log.shouldLog(Log.INFO))
_log.info("Got " + pids.size() + " from PEX");
List<Peer> peers = new ArrayList(pids.size());
for (PeerID pID : pids) {
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
}
Random r = _util.getContext().random();
Collections.shuffle(peers, r);
Iterator<Peer> it = peers.iterator();
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
Peer cur = it.next();
if (coordinator.addPeer(cur) && it.hasNext()) {
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
rv = pids.size();
pids.clear();
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Not getting PEX peers");
}
return rv;
}
/**
* @return max peers seen
*/
private int getPeersFromDHT() {
// Get peers from DHT
// FIXME this needs to be in its own thread
int rv = 0;
DHT dht = _util.getDHT();
if (dht != null && (meta == null || !meta.isPrivate()) && (!stop) &&
_util.getContext().clock().now() > lastDHTAnnounce + MIN_DHT_ANNOUNCE_INTERVAL) {
int numwant;
if (!coordinator.needOutboundPeers())
numwant = 1;
else
numwant = _util.getMaxConnections();
Collection<Hash> hashes = dht.getPeers(snark.getInfoHash(), numwant, 2*60*1000);
if (!hashes.isEmpty()) {
runStarted = true;
lastDHTAnnounce = _util.getContext().clock().now();
rv = hashes.size();
}
if (_log.shouldLog(Log.INFO))
_log.info("Got " + hashes + " from DHT");
// announce ourselves while the token is still good
// FIXME this needs to be in its own thread
if (!stop) {
// announce only to the 1 closest
int good = dht.announce(snark.getInfoHash(), 1, 5*60*1000);
if (_log.shouldLog(Log.INFO))
_log.info("Sent " + good + " good announces to DHT");
}
// now try these peers
if ((!stop) && !hashes.isEmpty()) {
List<Peer> peers = new ArrayList(hashes.size());
for (Hash h : hashes) {
try {
PeerID pID = new PeerID(h.getData(), _util);
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
} catch (InvalidBEncodingException ibe) {}
}
Random r = _util.getContext().random();
Collections.shuffle(peers, r);
Iterator<Peer> it = peers.iterator();
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
Peer cur = it.next();
if (coordinator.addPeer(cur) && it.hasNext()) {
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
}
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Not getting DHT peers");
}
return rv;
}
/**
* Creates a thread for each tracker in parallel if tunnel is still open
* @since 0.9.1
@@ -557,7 +658,7 @@ public class TrackerClient implements Runnable {
if (dht != null)
dht.unannounce(snark.getInfoHash());
int i = 0;
for (Tracker tr : trackers) {
for (TCTracker tr : trackers) {
if (_util.connected() &&
tr.started && (!tr.stop) && tr.trackerProblems == null) {
try {
@@ -577,9 +678,9 @@ public class TrackerClient implements Runnable {
* @since 0.9.1
*/
private class Unannouncer implements Runnable {
private final Tracker tr;
private final TCTracker tr;
public Unannouncer(Tracker tr) {
public Unannouncer(TCTracker tr) {
this.tr = tr;
}
@@ -603,7 +704,7 @@ public class TrackerClient implements Runnable {
}
}
private TrackerInfo doRequest(Tracker tr, String infoHash,
private TrackerInfo doRequest(TCTracker tr, String infoHash,
String peerID, long uploaded,
long downloaded, long left, String event)
throws IOException
@@ -630,7 +731,8 @@ public class TrackerClient implements Runnable {
if (! event.equals(NO_EVENT))
buf.append("&event=").append(event);
buf.append("&numwant=");
if (left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needOutboundPeers())
boolean small = left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needOutboundPeers();
if (small)
buf.append('0');
else
buf.append(_util.getMaxConnections());
@@ -641,14 +743,12 @@ public class TrackerClient implements Runnable {
tr.lastRequestTime = System.currentTimeMillis();
// Don't wait for a response to stopped when shutting down
boolean fast = _fastUnannounce && event.equals(STOPPED_EVENT);
File fetched = _util.get(s, true, fast ? -1 : 0);
byte[] fetched = _util.get(s, true, fast ? -1 : 0, small ? 128 : 1024, small ? 1024 : 8*1024);
if (fetched == null) {
throw new IOException("Error fetching " + s);
}
InputStream in = null;
try {
in = new FileInputStream(fetched);
InputStream in = new ByteArrayInputStream(fetched);
TrackerInfo info = new TrackerInfo(in, snark.getID(),
snark.getInfoHash(), snark.getMetaInfo(), _util);
@@ -661,10 +761,6 @@ public class TrackerClient implements Runnable {
tr.interval = Math.max(MIN_TRACKER_ANNOUNCE_INTERVAL, info.getInterval() * 1000l);
return info;
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
fetched.delete();
}
}
/**
@@ -698,6 +794,7 @@ public class TrackerClient implements Runnable {
}
/**
* @param ann an announce URL
* @return true for i2p hosts only
* @since 0.7.12
*/
@@ -713,10 +810,38 @@ public class TrackerClient implements Runnable {
url.getPort() < 0;
}
private static class Tracker
/**
* @param ann an announce URL non-null
* @return a Hash for i2p hosts only, null otherwise
* @since 0.9.5
*/
private static Hash getHostHash(String ann) {
URL url;
try {
url = new URL(ann);
} catch (MalformedURLException mue) {
return null;
}
if (url.getPort() >= 0 || !url.getProtocol().equals("http"))
return null;
String host = url.getHost();
if (host.endsWith(".i2p"))
return ConvertToHash.getHash(host);
if (host.equals("i2p")) {
String path = url.getPath();
if (path == null || path.length() < 517 ||
!path.startsWith("/"))
return null;
String[] parts = path.substring(1).split("/?&;", 2);
return ConvertToHash.getHash(parts[0]);
}
return null;
}
private static class TCTracker
{
String announce;
boolean isPrimary;
final String announce;
final boolean isPrimary;
long interval;
long lastRequestTime;
String trackerProblems;
@@ -726,7 +851,7 @@ public class TrackerClient implements Runnable {
int consecutiveFails;
int seenPeers;
public Tracker(String a, boolean p)
public TCTracker(String a, boolean p)
{
announce = a;
isPrimary = p;

View File

@@ -0,0 +1,52 @@
package org.klomp.snark;
import java.net.URI;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.update.*;
/**
* <p>Handles the request to update the router by firing up a magnet.
* {@link net.i2p.util.EepGet} calls to download the latest signed update file
* and displaying the status to anyone who asks.
* </p>
* <p>After the download completes the signed update file is verified with
* {@link net.i2p.crypto.TrustedUpdate}, and if it's authentic the payload
* of the signed update file is unpacked and the router is restarted to complete
* the update process.
* </p>
*
* This does not do any checking, that is handled by the NewsFetcher.
*
* @since 0.9.4
*/
class UpdateHandler implements Updater {
private final I2PAppContext _context;
private final UpdateManager _umgr;
private final SnarkManager _smgr;
public UpdateHandler(I2PAppContext ctx, UpdateManager umgr, SnarkManager smgr) {
_context = ctx;
_umgr = umgr;
_smgr = smgr;
}
/**
* Start a download and return a handle to the download task.
* Should not block.
*
* @param id plugin name or ignored
* @param maxTime how long you have
* @return active task or null if unable to download
*/
public UpdateTask update(UpdateType type, UpdateMethod method, List<URI> updateSources,
String id, String newVersion, long maxTime) {
if (type != UpdateType.ROUTER_SIGNED ||
method != UpdateMethod.TORRENT || updateSources.isEmpty())
return null;
UpdateRunner update = new UpdateRunner(_context, _umgr, _smgr, updateSources, newVersion);
_umgr.notifyProgress(update, "<b>" + _smgr.util().getString("Updating") + "</b>");
return update;
}
}

View File

@@ -0,0 +1,302 @@
package org.klomp.snark;
import java.io.File;
import java.net.URI;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.crypto.TrustedUpdate;
import net.i2p.data.DataHelper;
import net.i2p.update.*;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer2;
import net.i2p.util.VersionComparator;
/**
* The downloader for router signed updates.
*
* @since 0.9.4
*/
class UpdateRunner implements UpdateTask, CompleteListener {
private final I2PAppContext _context;
private final Log _log;
private final UpdateManager _umgr;
private final SnarkManager _smgr;
private final List<URI> _urls;
private volatile boolean _isRunning;
private volatile boolean _hasMetaInfo;
private volatile boolean _isComplete;
private final String _newVersion;
private URI _currentURI;
private Snark _snark;
private static final long MAX_LENGTH = 30*1024*1024;
private static final long METAINFO_TIMEOUT = 30*60*1000;
private static final long COMPLETE_TIMEOUT = 3*60*60*1000;
private static final long CHECK_INTERVAL = 3*60*1000;
public UpdateRunner(I2PAppContext ctx, UpdateManager umgr, SnarkManager smgr,
List<URI> uris, String newVersion) {
_context = ctx;
_log = ctx.logManager().getLog(getClass());
_umgr = umgr;
_smgr = smgr;
_urls = uris;
_newVersion = newVersion;
}
//////// begin UpdateTask methods
public boolean isRunning() { return _isRunning; }
public void shutdown() {
_isRunning = false;
if (_snark != null) {
}
}
public UpdateType getType() { return UpdateType.ROUTER_SIGNED; }
public UpdateMethod getMethod() { return UpdateMethod.TORRENT; }
public URI getURI() { return _currentURI; }
public String getID() { return ""; }
//////// end UpdateTask methods
public void start() {
_isRunning = true;
update();
}
/**
* Loop through the entire list of update URLs.
* For each one, first get the version from the first 56 bytes and see if
* it is newer than what we are running now.
* If it is, get the whole thing.
*/
private void update() {
for (URI uri : _urls) {
_currentURI = uri;
String updateURL = uri.toString();
try {
MagnetURI magnet = new MagnetURI(_smgr.util(), updateURL);
byte[] ih = magnet.getInfoHash();
// do we already have it?
_snark = _smgr.getTorrentByInfoHash(ih);
if (_snark != null) {
if (_snark.getMetaInfo() != null) {
_hasMetaInfo = true;
Storage storage = _snark.getStorage();
if (storage != null && storage.complete())
processComplete(_snark);
}
if (!_isComplete) {
if (_snark.isStopped() && !_snark.isStarting())
_snark.startTorrent();
// we aren't a listener so we must poll
new Watcher();
}
break;
}
String name = magnet.getName();
String trackerURL = magnet.getTrackerURL();
if (trackerURL == null && !_smgr.util().shouldUseDHT() &&
!_smgr.util().shouldUseOpenTrackers()) {
// but won't we use OT as a failsafe even if disabled?
_umgr.notifyAttemptFailed(this, "No tracker, no DHT, no OT", null);
continue;
}
_snark = _smgr.addMagnet(name, ih, trackerURL, true, true, this);
if (_snark != null) {
updateStatus("<b>" + _smgr.util().getString("Updating from {0}", updateURL) + "</b>");
new Timeout();
break;
}
} catch (IllegalArgumentException iae) {
_log.error("Invalid update URL", iae);
}
}
if (_snark == null)
fatal("No valid URLs");
}
/**
* This will run twice, once at the metainfo timeout and
* once at the complete timeout.
*/
private class Timeout extends SimpleTimer2.TimedEvent {
private final long _start = _context.clock().now();
public Timeout() {
super(_context.simpleTimer2(), METAINFO_TIMEOUT);
}
public void timeReached() {
if (_isComplete || !_isRunning)
return;
if (!_hasMetaInfo) {
fatal("Metainfo timeout");
return;
}
if (_context.clock().now() - _start >= COMPLETE_TIMEOUT) {
fatal("Complete timeout");
return;
}
reschedule(COMPLETE_TIMEOUT - METAINFO_TIMEOUT);
}
}
/**
* Rarely used - only if the user added the torrent, so
* we aren't a complete listener.
* This will periodically until the complete timeout.
*/
private class Watcher extends SimpleTimer2.TimedEvent {
private final long _start = _context.clock().now();
public Watcher() {
super(_context.simpleTimer2(), CHECK_INTERVAL);
}
public void timeReached() {
if (_hasMetaInfo && _snark.getRemainingLength() == 0 && !_isComplete)
processComplete(_snark);
if (_isComplete || !_isRunning)
return;
if (_context.clock().now() - _start >= METAINFO_TIMEOUT && !_hasMetaInfo) {
fatal("Metainfo timeout");
return;
}
if (_context.clock().now() - _start >= COMPLETE_TIMEOUT) {
fatal("Complete timeout");
return;
}
notifyProgress();
reschedule(CHECK_INTERVAL);
}
}
private void fatal(String error) {
if (_snark != null) {
if (_hasMetaInfo) {
_smgr.stopTorrent(_snark, true);
String file = _snark.getName();
_smgr.removeTorrent(file);
// delete torrent file
File f = new File(_smgr.getDataDir(), file);
f.delete();
// delete data
file = _snark.getBaseName();
f = new File(_smgr.getDataDir(), file);
f.delete();
} else {
_smgr.deleteMagnet(_snark);
}
}
_umgr.notifyTaskFailed(this, error, null);
_log.error(error);
_isRunning = false;
// stop the tunnel if we were the only one running
if (_smgr.util().connected() && !_smgr.util().isConnecting()) {
for (Snark s : _smgr.getTorrents()) {
if (!s.isStopped())
return;
}
_smgr.util().disconnect();
}
}
private void processComplete(Snark snark) {
String dataFile = snark.getBaseName();
File f = new File(_smgr.getDataDir(), dataFile);
String sudVersion = TrustedUpdate.getVersionString(f);
if (_newVersion.equals(sudVersion))
_umgr.notifyComplete(this, _newVersion, f);
else
fatal("version mismatch");
_isComplete = true;
}
private void notifyProgress() {
if (_hasMetaInfo) {
long total = _snark.getTotalLength();
long remaining = _snark.getRemainingLength();
String status = "<b>" + _smgr.util().getString("Updating") + "</b>";
_umgr.notifyProgress(this, status, total - remaining, total);
}
}
//////// begin CompleteListener methods
//////// all pass through to SnarkManager
public void torrentComplete(Snark snark) {
processComplete(snark);
_smgr.torrentComplete(snark);
}
/**
* This is called by stopTorrent() among others
*/
public void updateStatus(Snark snark) {
if (snark.isStopped()) {
if (!_isComplete)
fatal("stopped by user");
}
_smgr.updateStatus(snark);
}
public String gotMetaInfo(Snark snark) {
MetaInfo info = snark.getMetaInfo();
if (info.getFiles() != null) {
fatal("more than 1 file");
return null;
}
if (info.isPrivate()) {
fatal("private torrent");
return null;
}
if (info.getTotalLength() > MAX_LENGTH) {
fatal("too big");
return null;
}
_hasMetaInfo = true;
notifyProgress();
return _smgr.gotMetaInfo(snark);
}
public void fatal(Snark snark, String error) {
fatal(error);
_smgr.fatal(snark, error);
}
public void addMessage(Snark snark, String message) {
_smgr.addMessage(snark, message);
}
public void gotPiece(Snark snark) {
notifyProgress();
_smgr.gotPiece(snark);
}
public long getSavedTorrentTime(Snark snark) {
return _smgr.getSavedTorrentTime(snark);
}
public BitField getSavedTorrentBitField(Snark snark) {
return _smgr.getSavedTorrentBitField(snark);
}
//////// end CompleteListener methods
private void updateStatus(String s) {
_umgr.notifyProgress(this, s);
}
@Override
public String toString() {
return getClass().getName() + ' ' + getType() + ' ' + getID() + ' ' + getMethod() + ' ' + getURI();
}
}

View File

@@ -69,6 +69,9 @@ class DHTNodes {
// begin ConcurrentHashMap methods
/**
* @return known nodes, not total net size
*/
public int size() {
return _nodeMap.size();
}
@@ -86,8 +89,13 @@ class DHTNodes {
* @return the old value if present, else null
*/
public NodeInfo putIfAbsent(NodeInfo nInfo) {
_kad.add(nInfo.getNID());
return _nodeMap.putIfAbsent(nInfo.getNID(), nInfo);
NodeInfo rv = _nodeMap.putIfAbsent(nInfo.getNID(), nInfo);
// ensure same object in both places
if (rv != null)
_kad.add(rv.getNID());
else
_kad.add(nInfo.getNID());
return rv;
}
public NodeInfo remove(NID nid) {
@@ -128,11 +136,19 @@ class DHTNodes {
return _kad.getExploreKeys(MAX_BUCKET_AGE);
}
/**
* Debug info, HTML formatted
* @since 0.9.4
*/
public void renderStatusHTML(StringBuilder buf) {
buf.append(_kad.toString().replace("\n", "<br>\n"));
}
/** */
private class Cleaner extends SimpleTimer2.TimedEvent {
public Cleaner() {
super(SimpleTimer2.getInstance(), CLEAN_TIME);
super(SimpleTimer2.getInstance(), 5 * CLEAN_TIME);
}
public void timeReached() {

View File

@@ -39,6 +39,8 @@ class DHTTracker {
private static final long DELTA_EXPIRE_TIME = 3*60*1000;
private static final int MAX_PEERS = 2000;
private static final int MAX_PEERS_PER_TORRENT = 150;
private static final int ABSOLUTE_MAX_PER_TORRENT = MAX_PEERS_PER_TORRENT * 2;
private static final int MAX_TORRENTS = 400;
DHTTracker(I2PAppContext ctx) {
_context = ctx;
@@ -62,17 +64,29 @@ class DHTTracker {
_log.debug("Announce " + hash + " for " + ih);
Peers peers = _torrents.get(ih);
if (peers == null) {
if (_torrents.size() >= MAX_TORRENTS)
return;
peers = new Peers();
Peers peers2 = _torrents.putIfAbsent(ih, peers);
if (peers2 != null)
peers = peers2;
}
Peer peer = new Peer(hash.getData());
Peer peer2 = peers.putIfAbsent(peer, peer);
if (peer2 != null)
peer = peer2;
peer.setLastSeen(_context.clock().now());
if (peers.size() < ABSOLUTE_MAX_PER_TORRENT) {
Peer peer = new Peer(hash.getData());
Peer peer2 = peers.putIfAbsent(peer, peer);
if (peer2 != null)
peer = peer2;
peer.setLastSeen(_context.clock().now());
} else {
// We could update setLastSeen if he is already
// in there, but that would tend to keep
// the same set of peers.
// So let it expire so new ones can come in.
//Peer peer = peers.get(hash);
//if (peer != null)
// peer.setLastSeen(_context.clock().now());
}
}
void unannounce(InfoHash ih, Hash hash) {
@@ -113,7 +127,7 @@ class DHTTracker {
private class Cleaner extends SimpleTimer2.TimedEvent {
public Cleaner() {
super(SimpleTimer2.getInstance(), CLEAN_TIME);
super(SimpleTimer2.getInstance(), 2 * CLEAN_TIME);
}
public void timeReached() {
@@ -122,6 +136,7 @@ class DHTTracker {
long now = _context.clock().now();
int torrentCount = 0;
int peerCount = 0;
boolean tooMany = false;
for (Iterator<Peers> iter = _torrents.values().iterator(); iter.hasNext(); ) {
Peers p = iter.next();
int recent = 0;
@@ -136,6 +151,7 @@ class DHTTracker {
}
if (recent > MAX_PEERS_PER_TORRENT) {
// too many, delete at random
// TODO sort and remove oldest?
// TODO per-torrent adjustable expiration?
for (Iterator<Peer> iterp = p.values().iterator(); iterp.hasNext() && p.size() > MAX_PEERS_PER_TORRENT; ) {
iterp.next();
@@ -143,6 +159,7 @@ class DHTTracker {
peerCount--;
}
torrentCount++;
tooMany = true;
} else if (recent <= 0) {
iter.remove();
} else {
@@ -151,6 +168,8 @@ class DHTTracker {
}
if (peerCount > MAX_PEERS)
tooMany = true;
if (tooMany)
_expireTime = Math.max(_expireTime - DELTA_EXPIRE_TIME, MIN_EXPIRE_TIME);
else
_expireTime = Math.min(_expireTime + DELTA_EXPIRE_TIME, MAX_EXPIRE_TIME);
@@ -162,7 +181,7 @@ class DHTTracker {
DataHelper.formatDuration(_expireTime) + " expiration");
_peerCount = peerCount;
_torrentCount = torrentCount;
schedule(CLEAN_TIME);
schedule(tooMany ? CLEAN_TIME / 3 : CLEAN_TIME);
}
}
}

View File

@@ -38,6 +38,7 @@ import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.data.SimpleDataStructure;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer2;
@@ -97,6 +98,8 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
private final ConcurrentHashMap<Token, NodeInfo> _outgoingTokens;
/** index to incoming opaque tokens, received in a peers or nodes reply */
private final ConcurrentHashMap<NID, Token> _incomingTokens;
/** recently unreachable, with lastSeen() as the added-to-blacklist time */
private final Set<NID> _blacklist;
/** hook to inject and receive datagrams */
private final I2PSession _session;
@@ -111,6 +114,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
/** signed dgrams */
private final int _qPort;
private final File _dhtFile;
private final File _backupDhtFile;
private volatile boolean _isRunning;
private volatile boolean _hasBootstrapped;
/** stats */
@@ -140,6 +144,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
/** how long since generated do we delete - BEP 5 says 10 minutes */
private static final long MAX_TOKEN_AGE = 10*60*1000;
private static final long MAX_INBOUND_TOKEN_AGE = MAX_TOKEN_AGE - 2*60*1000;
private static final int MAX_OUTBOUND_TOKENS = 5000;
/** how long since sent do we wait for a reply */
private static final long MAX_MSGID_AGE = 2*60*1000;
/** how long since sent do we wait for a reply */
@@ -147,12 +152,16 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
/** stagger with other cleaners */
private static final long CLEAN_TIME = 63*1000;
private static final long EXPLORE_TIME = 877*1000;
private static final String DHT_FILE = "i2psnark.dht.dat";
private static final long BLACKLIST_CLEAN_TIME = 17*60*1000;
private static final String DHT_FILE_SUFFIX = ".dht.dat";
private static final int SEND_CRYPTO_TAGS = 8;
private static final int LOW_CRYPTO_TAGS = 4;
public KRPC (I2PAppContext ctx, I2PSession session) {
/**
* @param baseName generally "i2psnark"
*/
public KRPC(I2PAppContext ctx, String baseName, I2PSession session) {
_context = ctx;
_session = session;
_log = ctx.logManager().getLog(KRPC.class);
@@ -161,6 +170,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
_sentQueries = new ConcurrentHashMap();
_outgoingTokens = new ConcurrentHashMap();
_incomingTokens = new ConcurrentHashMap();
_blacklist = new ConcurrentHashSet();
// Construct my NodeInfo
// Pick ports over a big range to marginally increase security
@@ -176,7 +186,8 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
_myNID = new NID(_myID);
}
_myNodeInfo = new NodeInfo(_myNID, session.getMyDestination(), _qPort);
_dhtFile = new File(ctx.getConfigDir(), DHT_FILE);
_dhtFile = new File(ctx.getConfigDir(), baseName + DHT_FILE_SUFFIX);
_backupDhtFile = baseName.equals("i2psnark") ? null : new File(ctx.getConfigDir(), "i2psnark" + DHT_FILE_SUFFIX);
_knownNodes = new DHTNodes(ctx, _myNID);
start();
@@ -262,13 +273,13 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
int replyType = waiter.getReplyCode();
if (replyType == REPLY_NONE) {
if (_log.shouldLog(Log.INFO))
_log.info("Got no reply");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got no reply");
} else if (replyType == REPLY_NODES) {
List<NodeInfo> reply = (List<NodeInfo>) waiter.getReplyObject();
// It seems like we are just going to get back ourselves all the time
if (_log.shouldLog(Log.INFO))
_log.info("Got " + reply.size() + " nodes");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got " + reply.size() + " nodes");
for (NodeInfo ni : reply) {
if (! (ni.equals(_myNodeInfo) || (toTry.contains(ni) && tried.contains(ni))))
toTry.add(ni);
@@ -348,14 +359,14 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
int replyType = waiter.getReplyCode();
if (replyType == REPLY_NONE) {
if (_log.shouldLog(Log.INFO))
_log.info("Got no reply");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got no reply");
} else if (replyType == REPLY_PONG) {
if (_log.shouldLog(Log.INFO))
_log.info("Got pong");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got pong");
} else if (replyType == REPLY_PEERS) {
if (_log.shouldLog(Log.INFO))
_log.info("Got peers");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got peers");
List<Hash> reply = (List<Hash>) waiter.getReplyObject();
if (!reply.isEmpty()) {
for (int j = 0; j < reply.size() && rv.size() < max; j++) {
@@ -367,8 +378,8 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
}
} else if (replyType == REPLY_NODES) {
List<NodeInfo> reply = (List<NodeInfo>) waiter.getReplyObject();
if (_log.shouldLog(Log.INFO))
_log.info("Got " + reply.size() + " nodes");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got " + reply.size() + " nodes");
for (NodeInfo ni : reply) {
if (! (ni.equals(_myNodeInfo) || tried.contains(ni) || toTry.contains(ni)))
toTry.add(ni);
@@ -541,7 +552,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
_session.addMuxedSessionListener(this, I2PSession.PROTO_DATAGRAM, _qPort);
_knownNodes.start();
_tracker.start();
PersistDHT.loadDHT(this, _dhtFile);
PersistDHT.loadDHT(this, _dhtFile, _backupDhtFile);
// start the explore thread
_isRunning = true;
// no need to keep ref, it will eventually stop
@@ -567,7 +578,9 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
_session.removeListener(I2PSession.PROTO_DATAGRAM_RAW, _rPort);
// clear the DHT and tracker
_tracker.stop();
PersistDHT.saveDHT(_knownNodes, _dhtFile);
// don't lose all our peers if we didn't have time to check them
boolean saveAll = _context.clock().now() - _started < 20*60*1000;
PersistDHT.saveDHT(_knownNodes, saveAll, _dhtFile);
_knownNodes.stop();
for (Iterator<ReplyWaiter> iter = _sentQueries.values().iterator(); iter.hasNext(); ) {
ReplyWaiter waiter = iter.next();
@@ -576,6 +589,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
}
_outgoingTokens.clear();
_incomingTokens.clear();
_blacklist.clear();
}
/**
@@ -592,7 +606,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
*/
public String renderStatusHTML() {
long uptime = Math.max(1000, _context.clock().now() - _started);
StringBuilder buf = new StringBuilder();
StringBuilder buf = new StringBuilder(256);
buf.append("<br><b>DHT DEBUG</b><br>TX: ").append(_txPkts.get()).append(" pkts / ")
.append(DataHelper.formatSize2(_txBytes.get())).append("B / ")
.append(DataHelper.formatSize2(_txBytes.get() * 1000 / uptime)).append("Bps<br>" +
@@ -600,10 +614,12 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
.append(DataHelper.formatSize2(_rxBytes.get())).append("B / ")
.append(DataHelper.formatSize2(_rxBytes.get() * 1000 / uptime)).append("Bps<br>" +
"DHT Peers: ").append( _knownNodes.size()).append("<br>" +
"Blacklisted: ").append(_blacklist.size()).append("<br>" +
"Sent tokens: ").append(_outgoingTokens.size()).append("<br>" +
"Rcvd tokens: ").append(_incomingTokens.size()).append("<br>" +
"Pending queries: ").append(_sentQueries.size()).append("<br>");
_tracker.renderStatusHTML(buf);
_knownNodes.renderStatusHTML(buf);
return buf.toString();
}
@@ -1079,7 +1095,12 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
if (oldInfo.getDestination() == null && nInfo.getDestination() != null)
oldInfo.setDestination(nInfo.getDestination());
}
oldInfo.getNID().setLastSeen();
nID = oldInfo.getNID();
nID.setLastSeen();
if (_blacklist.remove(nID)) {
if (_log.shouldLog(Log.INFO))
_log.info("UN-blacklisted: " + nID);
}
return oldInfo;
}
@@ -1093,8 +1114,12 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
if (nInfo.equals(_myNodeInfo))
return _myNodeInfo;
NodeInfo rv = _knownNodes.putIfAbsent(nInfo);
if (rv == null)
if (rv == null) {
rv = nInfo;
// if we didn't know about it before, set the timestamp
// so it isn't immediately removed by the DHTNodes cleaner
rv.getNID().setLastSeen();
}
return rv;
}
@@ -1109,6 +1134,13 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
if (_log.shouldLog(Log.INFO))
_log.info("Removed after consecutive timeouts: " + nInfo);
}
if (!_blacklist.contains(nid)) {
// used as when-added time
nid.setLastSeen();
_blacklist.add(nid);
if (_log.shouldLog(Log.INFO))
_log.info("Blacklisted: " + nid);
}
}
}
@@ -1182,7 +1214,8 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
/**
* Handle and respond to the query.
* We have no node info here, it came on response port, we have to get it from the token
* We have no node info here, it came on response port, we have to get it from the token.
* So we can't verify that it came from the same peer, as BEP 5 specifies.
*/
private void receiveAnnouncePeer(MsgID msgID, InfoHash ih, byte[] tok) throws InvalidBEncodingException {
Token token = new Token(tok);
@@ -1190,8 +1223,8 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
if (nInfo == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Unknown token in announce_peer: " + token);
if (_log.shouldLog(Log.INFO))
_log.info("Current known tokens: " + _outgoingTokens.keySet());
//if (_log.shouldLog(Log.INFO))
// _log.info("Current known tokens: " + _outgoingTokens.keySet());
return;
}
if (_log.shouldLog(Log.INFO))
@@ -1223,11 +1256,11 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
byte[] tok = btok.getBytes();
Token token = new Token(_context, tok);
_incomingTokens.put(nInfo.getNID(), token);
if (_log.shouldLog(Log.INFO))
_log.info("Got token: " + token + ", must be a response to get_peers");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got token: " + token + ", must be a response to get_peers");
} else {
if (_log.shouldLog(Log.INFO))
_log.info("No token and saved infohash, must be a response to find_node");
if (_log.shouldLog(Log.DEBUG))
_log.debug("No token and saved infohash, must be a response to find_node");
}
}
@@ -1256,9 +1289,15 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
* @throws NPE, IllegalArgumentException, and others too
*/
private List<NodeInfo> receiveNodes(NodeInfo nInfo, byte[] ids) throws InvalidBEncodingException {
List<NodeInfo> rv = new ArrayList(ids.length / NodeInfo.LENGTH);
for (int off = 0; off < ids.length; off += NodeInfo.LENGTH) {
int max = Math.min(K, ids.length / NodeInfo.LENGTH);
List<NodeInfo> rv = new ArrayList(max);
for (int off = 0; off < ids.length && rv.size() < max; off += NodeInfo.LENGTH) {
NodeInfo nInf = new NodeInfo(ids, off);
if (_blacklist.contains(nInf.getNID())) {
if (_log.shouldLog(Log.INFO))
_log.info("Ignoring blacklisted " + nInf.getNID() + " from: " + nInfo);
continue;
}
nInf = heardAbout(nInf);
rv.add(nInf);
}
@@ -1274,12 +1313,15 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
private List<Hash> receivePeers(NodeInfo nInfo, List<BEValue> peers) throws InvalidBEncodingException {
if (_log.shouldLog(Log.INFO))
_log.info("Rcvd peers from: " + nInfo);
List<Hash> rv = new ArrayList(peers.size());
int max = Math.min(MAX_WANT, peers.size());
List<Hash> rv = new ArrayList(max);
for (BEValue bev : peers) {
byte[] b = bev.getBytes();
//Hash h = new Hash(b);
Hash h = Hash.create(b);
rv.add(h);
if (rv.size() >= max)
break;
}
if (_log.shouldLog(Log.INFO))
_log.info("Rcvd peers from: " + nInfo + ": " + DataHelper.toString(rv));
@@ -1492,7 +1534,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
private class Cleaner extends SimpleTimer2.TimedEvent {
public Cleaner() {
super(SimpleTimer2.getInstance(), CLEAN_TIME);
super(SimpleTimer2.getInstance(), 7 * CLEAN_TIME);
}
public void timeReached() {
@@ -1501,21 +1543,37 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
long now = _context.clock().now();
if (_log.shouldLog(Log.DEBUG))
_log.debug("KRPC cleaner starting with " +
_blacklist.size() + " in blacklist, " +
_outgoingTokens.size() + " sent Tokens, " +
_incomingTokens.size() + " rcvd Tokens");
int cnt = 0;
long expire = now - MAX_TOKEN_AGE;
for (Iterator<Token> iter = _outgoingTokens.keySet().iterator(); iter.hasNext(); ) {
Token tok = iter.next();
if (tok.lastSeen() < now - MAX_TOKEN_AGE)
// just delete at random if we have too many
// TODO reduce the expire time and iterate again?
if (tok.lastSeen() < expire || cnt >= MAX_OUTBOUND_TOKENS)
iter.remove();
else
cnt++;
}
expire = now - MAX_INBOUND_TOKEN_AGE;
for (Iterator<Token> iter = _incomingTokens.values().iterator(); iter.hasNext(); ) {
Token tok = iter.next();
if (tok.lastSeen() < now - MAX_INBOUND_TOKEN_AGE)
if (tok.lastSeen() < expire)
iter.remove();
}
expire = now - BLACKLIST_CLEAN_TIME;
for (Iterator<NID> iter = _blacklist.iterator(); iter.hasNext(); ) {
NID nid = iter.next();
// lastSeen() is actually when-added
if (nid.lastSeen() < expire)
iter.remove();
}
// TODO sent queries?
if (_log.shouldLog(Log.DEBUG))
_log.debug("KRPC cleaner done, now with " +
_blacklist.size() + " in blacklist, " +
_outgoingTokens.size() + " sent Tokens, " +
_incomingTokens.size() + " rcvd Tokens, " +
_knownNodes.size() + " known peers, " +

View File

@@ -18,7 +18,7 @@ public class NID extends SHA1Hash {
private long lastSeen;
private int fails;
private static final int MAX_FAILS = 3;
private static final int MAX_FAILS = 2;
public NID() {
super(null);
@@ -41,6 +41,6 @@ public class NID extends SHA1Hash {
* @return if more than max timeouts
*/
public boolean timeout() {
return fails++ > MAX_FAILS;
return ++fails > MAX_FAILS;
}
}

View File

@@ -23,6 +23,17 @@ abstract class PersistDHT {
private static final long MAX_AGE = 60*60*1000;
/**
* @param backupFile may be null
* @since 0.9.6
*/
public static synchronized void loadDHT(KRPC krpc, File file, File backupFile) {
if (file.exists())
loadDHT(krpc, file);
else if (backupFile != null)
loadDHT(krpc, backupFile);
}
public static synchronized void loadDHT(KRPC krpc, File file) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(PersistDHT.class);
int count = 0;
@@ -56,12 +67,15 @@ abstract class PersistDHT {
log.info("Loaded " + count + " nodes from " + file);
}
public static synchronized void saveDHT(DHTNodes nodes, File file) {
/**
* @param saveAll if true, don't check last seen time
*/
public static synchronized void saveDHT(DHTNodes nodes, boolean saveAll, File file) {
if (nodes.size() <= 0)
return;
Log log = I2PAppContext.getGlobalContext().logManager().getLog(PersistDHT.class);
int count = 0;
long maxAge = I2PAppContext.getGlobalContext().clock().now() - MAX_AGE;
long maxAge = saveAll ? 0 : I2PAppContext.getGlobalContext().clock().now() - MAX_AGE;
PrintWriter out = null;
try {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(file), "ISO-8859-1")));

View File

@@ -0,0 +1,599 @@
// ========================================================================
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package org.klomp.snark.web;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.util.ByteCache;
import net.i2p.util.Log;
/* ------------------------------------------------------------ */
/**
* Based on DefaultServlet from Jetty 6.1.26, heavily simplified
* and modified to remove all dependencies on Jetty libs.
*
* Supports HEAD and GET only, for resources from the .war and local files.
* Supports files and resource only.
* Supports MIME types with local overrides and additions.
* Supports Last-Modified.
* Supports single request ranges.
*
* Does not support directories or "welcome files".
* Does not support gzip.
* Does not support multiple request ranges.
* Does not cache.
*
* POST returns 405.
* Directories return 403.
* Jar resources are sent with a long cache directive.
*
* ------------------------------------------------------------
*
* The default servlet.
* This servlet, normally mapped to /, provides the handling for static
* content, OPTION and TRACE methods for the context.
* The following initParameters are supported, these can be set either
* on the servlet itself or as ServletContext initParameters with a prefix
* of org.mortbay.jetty.servlet.Default. :
* <PRE>
*
* resourceBase Set to replace the context resource base
* warBase Path allowed for resource in war
*
* </PRE>
*
*
* @author Greg Wilkins (gregw)
* @author Nigel Canonizado
*
* @since Jetty 7
*/
class BasicServlet extends HttpServlet
{
protected final I2PAppContext _context;
protected final Log _log;
protected File _resourceBase;
private String _warBase;
private final MimeTypes _mimeTypes;
/** same as PeerState.PARTSIZE */
private static final int BUFSIZE = 16*1024;
private ByteCache _cache = ByteCache.getInstance(16, BUFSIZE);
private static final int WAR_CACHE_CONTROL_SECS = 24*60*60;
private static final int FILE_CACHE_CONTROL_SECS = 24*60*60;
public BasicServlet() {
super();
_context = I2PAppContext.getGlobalContext();
_log = _context.logManager().getLog(getClass());
_mimeTypes = new MimeTypes();
}
/* ------------------------------------------------------------ */
public void init(ServletConfig cfg) throws ServletException {
super.init(cfg);
String rb=getInitParameter("resourceBase");
if (rb!=null)
{
File f = new File(rb);
setResourceBase(f);
}
String wb = getInitParameter("warBase");
if (wb != null)
setWarBase(wb);
}
/**
* Files are served from here
*/
protected void setResourceBase(File base) throws UnavailableException {
if (!base.isDirectory())
throw new UnavailableException("Resource base does not exist: " + base);
_resourceBase = base;
if (_log.shouldLog(Log.INFO))
_log.info("Resource base is " + _resourceBase);
}
/**
* Only paths starting with this in the path are served
*/
protected void setWarBase(String base) {
if (!base.startsWith("/"))
base = '/' + base;
if (!base.endsWith("/"))
base = base + '/';
_warBase = base;
if (_log.shouldLog(Log.INFO))
_log.info("War base is " + _warBase);
}
/** get Resource to serve.
* Map a path to a resource. The default implementation calls
* HttpContext.getResource but derived servlets may provide
* their own mapping.
* @param pathInContext The path to find a resource for.
* @return The resource to serve or null if not existing
*/
public File getResource(String pathInContext)
{
if (_resourceBase==null)
return null;
File r = null;
if (!pathInContext.contains("..") &&
!pathInContext.endsWith("/")) {
File f = new File(_resourceBase, pathInContext);
if (f.exists())
r = f;
}
return r;
}
/** get Resource to serve.
* Map a path to a resource. The default implementation calls
* HttpContext.getResource but derived servlets may provide
* their own mapping.
* @param pathInContext The path to find a resource for.
* @return The resource to serve or null. Returns null for directories
*/
public HttpContent getContent(String pathInContext)
{
if (_resourceBase==null)
return null;
HttpContent r = null;
if (_warBase != null && pathInContext.startsWith(_warBase)) {
r = new JarContent(pathInContext);
} else if (!pathInContext.contains("..") &&
!pathInContext.endsWith("/")) {
File f = new File(_resourceBase, pathInContext);
// exists && !directory
if (f.isFile())
r = new FileContent(f);
}
return r;
}
/* ------------------------------------------------------------ */
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// always starts with a '/'
String servletpath = request.getServletPath();
String pathInfo=request.getPathInfo();
// ??? right??
String pathInContext = addPaths(servletpath, pathInfo);
// Find the resource and content
try {
HttpContent content = getContent(pathInContext);
// Handle resource
if (content == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Not found: " + pathInContext);
response.sendError(404);
} else {
if (passConditionalHeaders(request, response, content)) {
if (_log.shouldLog(Log.INFO))
_log.info("Sending: " + content);
sendData(request, response, content);
} else {
if (_log.shouldLog(Log.INFO))
_log.info("Not modified: " + content);
}
}
}
catch(IllegalArgumentException e)
{
if (_log.shouldLog(Log.WARN))
_log.warn("Error sending " + pathInContext, e);
if(!response.isCommitted())
response.sendError(500, e.getMessage());
}
catch(IOException e)
{
if (_log.shouldLog(Log.WARN))
// typical browser abort
//_log.warn("Error sending", e);
_log.warn("Error sending " + pathInContext + ": " + e);
throw e;
}
}
/* ------------------------------------------------------------ */
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.sendError(405);
}
/* ------------------------------------------------------------ */
/* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doTrace(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doTrace(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.sendError(405);
}
protected void doOptions(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.sendError(405);
}
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.sendError(405);
}
/* ------------------------------------------------------------ */
/** Check modification date headers.
* @return true to keep going, false if handled here
*/
protected boolean passConditionalHeaders(HttpServletRequest request,HttpServletResponse response, HttpContent content)
throws IOException
{
try
{
if (!request.getMethod().equals("HEAD") ) {
long ifmsl=request.getDateHeader("If-Modified-Since");
if (ifmsl!=-1)
{
if (content.getLastModified()/1000 <= ifmsl/1000)
{
response.reset();
response.setStatus(304);
response.flushBuffer();
return false;
}
}
}
}
catch(IllegalArgumentException iae)
{
if(!response.isCommitted())
response.sendError(400, iae.getMessage());
throw iae;
}
return true;
}
/* ------------------------------------------------------------ */
protected void sendData(HttpServletRequest request,
HttpServletResponse response,
HttpContent content)
throws IOException
{
InputStream in =null;
try {
in = content.getInputStream();
} catch (IOException e) {
if (_log.shouldLog(Log.WARN))
_log.warn("Not found: " + content);
response.sendError(404);
return;
}
OutputStream out =null;
try {
out = response.getOutputStream();
} catch (IllegalStateException e) {
out = new WriterOutputStream(response.getWriter());
}
long content_length = content.getContentLength();
// see if there are any range headers
Enumeration reqRanges = request.getHeaders("Range");
if (reqRanges == null || !reqRanges.hasMoreElements()) {
// if there were no ranges, send entire entity
// Write content normally
writeHeaders(response,content,content_length);
if (content_length >= 0 && request.getMethod().equals("HEAD")) {
// if we know the content length, don't send it to be counted
if (_log.shouldLog(Log.INFO))
_log.info("HEAD: " + content);
} else {
// GET or unknown size for HEAD
copy(in, out);
}
return;
}
// Parse the satisfiable ranges
List<InclusiveByteRange> ranges = InclusiveByteRange.satisfiableRanges(reqRanges, content_length);
// if there are no satisfiable ranges, send 416 response
// Completely punt on multiple ranges (unlike Default)
if (ranges == null || ranges.size() != 1) {
writeHeaders(response, content, content_length);
response.setStatus(416);
response.setHeader("Content-Range", InclusiveByteRange.to416HeaderRangeString(content_length));
return;
}
// if there is only a single valid range (must be satisfiable
// since were here now), send that range with a 216 response
InclusiveByteRange singleSatisfiableRange = ranges.get(0);
long singleLength = singleSatisfiableRange.getSize(content_length);
writeHeaders(response, content, singleLength);
response.setStatus(206);
response.setHeader("Content-Range", singleSatisfiableRange.toHeaderRangeString(content_length));
copy(in, singleSatisfiableRange.getFirst(content_length), out, singleLength);
}
/* ------------------------------------------------------------ */
protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
throws IOException
{
if (content.getContentType()!=null && response.getContentType()==null)
response.setContentType(content.getContentType());
long lml = content.getLastModified();
if (lml > 0)
response.setDateHeader("Last-Modified",lml);
if (count != -1)
{
if (count<Integer.MAX_VALUE)
response.setContentLength((int)count);
else
response.setHeader("Content-Length", Long.toString(count));
}
long ct = content.getCacheTime();
if (ct>=0)
response.setHeader("Cache-Control", "public, max-age=" + ct);
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* I2P additions below here */
/** from Jetty HttpContent.java */
public interface HttpContent
{
String getContentType();
long getLastModified();
/** in seconds */
int getCacheTime();
long getContentLength();
InputStream getInputStream() throws IOException;
}
private class FileContent implements HttpContent
{
private final File _file;
public FileContent(File file)
{
_file = file;
}
/* ------------------------------------------------------------ */
public String getContentType()
{
//return _mimeTypes.getMimeByExtension(_file.toString());
return getMimeType(_file.toString());
}
/* ------------------------------------------------------------ */
public long getLastModified()
{
return _file.lastModified();
}
public int getCacheTime()
{
return FILE_CACHE_CONTROL_SECS;
}
/* ------------------------------------------------------------ */
public long getContentLength()
{
return _file.length();
}
/* ------------------------------------------------------------ */
public InputStream getInputStream() throws IOException
{
return new BufferedInputStream(new FileInputStream(_file));
}
@Override
public String toString() { return "File \"" + _file + '"'; }
}
private class JarContent implements HttpContent
{
private final String _path;
public JarContent(String path)
{
_path = path;
}
/* ------------------------------------------------------------ */
public String getContentType()
{
return getMimeType(_path);
}
/* ------------------------------------------------------------ */
public long getLastModified()
{
String cpath = getServletContext().getContextPath();
// this won't work if we aren't at top level
String cname = cpath == "" ? "i2psnark" : cpath.substring(1).replace("/", "_");
return (new File(_context.getBaseDir(), "webapps/" + cname + ".war")).lastModified();
}
public int getCacheTime()
{
return WAR_CACHE_CONTROL_SECS;
}
/* ------------------------------------------------------------ */
public long getContentLength()
{
return -1;
}
/* ------------------------------------------------------------ */
public InputStream getInputStream() throws IOException
{
InputStream rv = getServletContext().getResourceAsStream(_path);
if (rv == null)
throw new IOException("Not found");
return rv;
}
@Override
public String toString() { return "Jar resource \"" + _path + '"'; }
}
/**
* @param resourcePath in the classpath, without ".properties" extension
*/
protected void loadMimeMap(String resourcePath) {
_mimeTypes.loadMimeMap(resourcePath);
}
/* ------------------------------------------------------------ */
/** Get the MIME type by filename extension.
* @param filename A file name
* @return MIME type matching the longest dot extension of the
* file name.
*/
protected String getMimeType(String filename) {
String rv = _mimeTypes.getMimeByExtension(filename);
if (rv != null)
return rv;
return getServletContext().getMimeType(filename);
}
protected void addMimeMapping(String extension, String type) {
_mimeTypes.addMimeMapping(extension, type);
}
/**
* Simple version of URIUtil.addPaths()
* @param path may be null
*/
protected static String addPaths(String base, String path) {
if (path == null)
return base;
return (new File(base, path)).toString();
}
/**
* Simple version of URIUtil.decodePath()
*/
protected static String decodePath(String path) throws MalformedURLException {
if (!path.contains("%"))
return path;
try {
URI uri = new URI(path);
return uri.getPath();
} catch (URISyntaxException use) {
// for ease of use, since a USE is not an IOE but a MUE is...
throw new MalformedURLException(use.getMessage());
}
}
/**
* Simple version of URIUtil.encodePath()
*/
protected static String encodePath(String path) throws MalformedURLException {
try {
URI uri = new URI(null, null, path, null);
return uri.toString();
} catch (URISyntaxException use) {
// for ease of use, since a USE is not an IOE but a MUE is...
throw new MalformedURLException(use.getMessage());
}
}
/**
* Write from in to out
*/
private void copy(InputStream in, OutputStream out) throws IOException {
copy(in, 0, out, -1);
}
/**
* Write from in to out
*/
private void copy(InputStream in, long skip, OutputStream out, final long len) throws IOException {
ByteArray ba = _cache.acquire();
byte[] buf = ba.getData();
try {
if (skip > 0)
in.skip(skip);
int read = 0;
long tot = 0;
boolean done = false;
while ( (read = in.read(buf)) != -1 && !done) {
if (len >= 0) {
tot += read;
if (tot >= len) {
read -= (int) (tot - len);
done = true;
}
}
out.write(buf, 0, read);
}
} finally {
_cache.release(ba, false);
if (in != null)
try { in.close(); } catch (IOException ioe) {}
if (out != null)
try { out.close(); } catch (IOException ioe) {}
}
}
}

View File

@@ -0,0 +1,218 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.klomp.snark.web;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;
/* ------------------------------------------------------------ */
/** Byte range inclusive of end points.
* <PRE>
*
* parses the following types of byte ranges:
*
* bytes=100-499
* bytes=-300
* bytes=100-
* bytes=1-2,2-3,6-,-2
*
* given an entity length, converts range to string
*
* bytes 100-499/500
*
* </PRE>
*
* Based on RFC2616 3.12, 14.16, 14.35.1, 14.35.2
* @version $version$
*
*/
public class InclusiveByteRange
{
long first = 0;
long last = 0;
public InclusiveByteRange(long first, long last)
{
this.first = first;
this.last = last;
}
public long getFirst()
{
return first;
}
public long getLast()
{
return last;
}
/* ------------------------------------------------------------ */
/**
* @param headers Enumeration of Range header fields.
* @param size Size of the resource.
* @return List of satisfiable ranges
*/
public static List<InclusiveByteRange> satisfiableRanges(Enumeration headers, long size)
{
List<InclusiveByteRange> satRanges = null;
// walk through all Range headers
headers:
while (headers.hasMoreElements())
{
String header = (String) headers.nextElement();
StringTokenizer tok = new StringTokenizer(header,"=,",false);
String t=null;
try
{
// read all byte ranges for this header
while (tok.hasMoreTokens())
{
try
{
t = tok.nextToken().trim();
long first = -1;
long last = -1;
int d = t.indexOf('-');
if (d < 0 || t.indexOf("-",d + 1) >= 0)
{
if ("bytes".equals(t))
continue;
continue headers;
}
else if (d == 0)
{
if (d + 1 < t.length())
last = Long.parseLong(t.substring(d + 1).trim());
else
{
continue;
}
}
else if (d + 1 < t.length())
{
first = Long.parseLong(t.substring(0,d).trim());
last = Long.parseLong(t.substring(d + 1).trim());
}
else
first = Long.parseLong(t.substring(0,d).trim());
if (first == -1 && last == -1)
continue headers;
if (first != -1 && last != -1 && (first > last))
continue headers;
if (first < size)
{
if (satRanges == null)
satRanges = new ArrayList(4);
InclusiveByteRange range = new InclusiveByteRange(first,last);
satRanges.add(range);
}
}
catch (NumberFormatException e)
{
continue;
}
}
}
catch(Exception e)
{
}
}
return satRanges;
}
/* ------------------------------------------------------------ */
public long getFirst(long size)
{
if (first<0)
{
long tf=size-last;
if (tf<0)
tf=0;
return tf;
}
return first;
}
/* ------------------------------------------------------------ */
public long getLast(long size)
{
if (first<0)
return size-1;
if (last<0 ||last>=size)
return size-1;
return last;
}
/* ------------------------------------------------------------ */
public long getSize(long size)
{
return getLast(size)-getFirst(size)+1;
}
/* ------------------------------------------------------------ */
public String toHeaderRangeString(long size)
{
StringBuilder sb = new StringBuilder(40);
sb.append("bytes ");
sb.append(getFirst(size));
sb.append('-');
sb.append(getLast(size));
sb.append("/");
sb.append(size);
return sb.toString();
}
/* ------------------------------------------------------------ */
public static String to416HeaderRangeString(long size)
{
StringBuilder sb = new StringBuilder(40);
sb.append("bytes */");
sb.append(size);
return sb.toString();
}
/* ------------------------------------------------------------ */
@Override
public String toString()
{
StringBuilder sb = new StringBuilder(60);
sb.append(Long.toString(first));
sb.append(":");
sb.append(Long.toString(last));
return sb.toString();
}
}

View File

@@ -0,0 +1,131 @@
// ========================================================================
// Copyright 2000-2005 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package org.klomp.snark.web;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletContext;
/* ------------------------------------------------------------ */
/**
* Based on MimeTypes from Jetty 6.1.26, heavily simplified
* and modified to remove all dependencies on Jetty libs.
*
* Supports mime types only, not encodings.
* Does not support a default "*" mapping.
*
* This is only for local mappings.
* Caller should use getServletContext().getMimeType() if this returns null.
*
*
* ------------------------------------------------------------
*
* @author Greg Wilkins
*
* @since Jetty 7
*/
class MimeTypes
{
private final Map<String, String> _mimeMap;
public MimeTypes() {
_mimeMap = new ConcurrentHashMap();
}
/* ------------------------------------------------------------ */
/**
* @param resourcePath A Map of file extension to mime-type.
*/
public void loadMimeMap(String resourcePath) {
loadMimeMap(_mimeMap, resourcePath);
}
/**
* Tries both webapp and system class loader, since Jetty blocks
* its classes from the webapp class loader.
*/
private static void loadMimeMap(Map<String, String> map, String resourcePath) {
try
{
ResourceBundle mime;
try {
mime = ResourceBundle.getBundle(resourcePath);
} catch(MissingResourceException e) {
// Jetty 7 webapp classloader blocks jetty classes
// http://wiki.eclipse.org/Jetty/Reference/Jetty_Classloading
//System.out.println("No mime types loaded from " + resourcePath + ", trying system classloader");
mime = ResourceBundle.getBundle(resourcePath, Locale.getDefault(), ClassLoader.getSystemClassLoader());
}
Enumeration<String> i = mime.getKeys();
while(i.hasMoreElements())
{
String ext = i.nextElement();
String m = mime.getString(ext);
map.put(ext.toLowerCase(Locale.US), m);
}
//System.out.println("Loaded " + map.size() + " mime types from " + resourcePath);
} catch(MissingResourceException e) {
//System.out.println("No mime types loaded from " + resourcePath);
}
}
/* ------------------------------------------------------------ */
/** Get the MIME type by filename extension.
*
* Returns ONLY local mappings.
* Caller should use getServletContext().getMimeType() if this returns null.
*
* @param filename A file name
* @return MIME type matching the longest dot extension of the
* file name.
*/
public String getMimeByExtension(String filename)
{
String type=null;
if (filename!=null)
{
int i=-1;
while(type==null)
{
i=filename.indexOf(".",i+1);
if (i<0 || i>=filename.length())
break;
String ext=filename.substring(i+1).toLowerCase(Locale.US);
type = _mimeMap.get(ext);
}
}
return type;
}
/* ------------------------------------------------------------ */
/** Set a mime mapping
* @param extension
* @param type
*/
public void addMimeMapping(String extension, String type)
{
_mimeMap.put(extension.toLowerCase(Locale.US), type);
}
}

View File

@@ -5,7 +5,7 @@ import java.io.File;
import net.i2p.I2PAppContext;
import net.i2p.util.FileUtil;
import org.mortbay.jetty.Server;
import org.eclipse.jetty.server.Server;
public class RunStandalone {
static {

View File

@@ -0,0 +1,19 @@
package org.klomp.snark.web;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
/**
* Treat a writer as an output stream. Quick 'n dirty, none
* of that "intarnasheeonaleyzayshun" stuff. So we can treat
* the jsp's PrintWriter as an OutputStream
*
* @since Jetty 7 copied from routerconsole
*/
class WriterOutputStream extends OutputStream {
private final Writer _writer;
public WriterOutputStream(Writer writer) { _writer = writer; }
public void write(int b) throws IOException { _writer.write(b); }
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
7z = application/x-7z-compressed
ape = audio/x-monkeys-audio
dmg = application/apple-diskimage
epub = application/epub+zip
flac = audio/flac
flv = video/x-flv
iso = application/x-iso9660-image
m4a = audio/mp4a-latm
m4v = video/x-m4v
mkv = video/x-matroska
mp4 = video/mp4
mpc = audio/x-musepack
nfo = text/plain
ogm = video/ogg
ogv = video/ogg
oga = audio/ogg
rar = application/x-rar-compressed
su2 = application/zip
sud = application/zip
txt = text/plain
war = application/java-archive
wma = audio/x-ms-wma
wmv = video/x-ms-wmv

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test/junit"/>
<classpathentry combineaccessrules="false" kind="src" path="/i2p_sdk"/>
<classpathentry combineaccessrules="false" kind="src" path="/ministreaming"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="build/obj"/>
</classpath>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>i2ptunnel</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -21,6 +21,9 @@
</depend>
</target>
<condition property="no.bundle">
<isfalse value="${require.gettext}" />
</condition>
<property name="javac.compilerargs" value="" />
<property name="require.gettext" value="true" />
@@ -84,7 +87,7 @@
</condition>
</target>
<target name="bundle" depends="compile, precompilejsp">
<target name="bundle" depends="compile, precompilejsp" unless="no.bundle">
<!-- Update the messages_*.po files.
We need to supply the bat file for windows, and then change the fail property to true -->
<exec executable="sh" osfamily="unix" failifexecutionfails="true" failonerror="${require.gettext}" >
@@ -179,6 +182,7 @@
<pathelement location="${ant.home}/lib/ant.jar" />
<pathelement location="build/i2ptunnel.jar" />
<pathelement location="build/temp-beans.jar" />
<pathelement location="../../../core/java/build/i2p.jar" />
</classpath>
<arg value="-d" />
<arg value="../jsp/WEB-INF/classes" />
@@ -202,6 +206,7 @@
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
<pathelement location="build/i2ptunnel.jar" />
<pathelement location="build/temp-beans.jar" />
<pathelement location="../../../core/java/build/i2p.jar" />
</classpath>
</javac>
<copy file="../jsp/web.xml" tofile="../jsp/web-out.xml" />
@@ -213,6 +218,7 @@
<uptodate property="precompilejsp.uptodate" targetfile="../jsp/web-out.xml">
<srcfiles dir= "../jsp" includes="*.jsp, *.html, web.xml"/>
<srcfiles dir= "src/net/i2p/i2ptunnel/web" includes="*.java"/>
</uptodate>
<target name="javadoc">
@@ -230,7 +236,7 @@
<mkdir dir="./build" />
<mkdir dir="./build/obj" />
<!-- We need the ant runtime, as it includes junit -->
<javac srcdir="./src:./test" debug="true" source="1.5" target="1.5"
<javac srcdir="./src:./test/junit" debug="true" source="1.5" target="1.5"
includeAntRuntime="true"
deprecation="on" destdir="./build/obj" >
<compilerarg line="${javac.compilerargs}" />
@@ -248,7 +254,7 @@
<pathelement location="../../../core/java/build/i2p.jar" />
</classpath>
<batchtest>
<fileset dir="./test/">
<fileset dir="./test/junit/">
<include name="**/*Test.java" />
</fileset>
</batchtest>

View File

@@ -1,4 +1,5 @@
#
#!/bin/sh
# Update messages_xx.po and messages_xx.class files,
# from both java and jsp sources.
# Requires installed programs xgettext, msgfmt, msgmerge, and find.

View File

@@ -54,9 +54,7 @@ class HTTPResponseOutputStream extends FilterOutputStream {
public HTTPResponseOutputStream(OutputStream raw) {
super(raw);
_context = I2PAppContext.getGlobalContext();
_context.statManager().createRateStat("i2ptunnel.httpCompressionRatio", "ratio of compressed size to decompressed size after transfer", "I2PTunnel", new long[] { 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.httpCompressed", "compressed size transferred", "I2PTunnel", new long[] { 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.httpExpanded", "size transferred after expansion", "I2PTunnel", new long[] { 60*60*1000 });
// all createRateStat in I2PTunnelHTTPClient.startRunning()
_log = _context.logManager().getLog(getClass());
_headerBuffer = _cache.acquire();
_buf1 = new byte[1];
@@ -67,10 +65,12 @@ class HTTPResponseOutputStream extends FilterOutputStream {
_buf1[0] = (byte)c;
write(_buf1, 0, 1);
}
@Override
public void write(byte buf[]) throws IOException {
write(buf, 0, buf.length);
}
@Override
public void write(byte buf[], int off, int len) throws IOException {
if (_headerWritten) {
@@ -183,6 +183,7 @@ class HTTPResponseOutputStream extends FilterOutputStream {
_gzip = true;
} else if ("proxy-authenticate".equals(lcKey)) {
// filter this hop-by-hop header; outproxy authentication must be configured in I2PTunnelHTTPClient
// see e.g. http://blog.c22.cc/2013/03/11/privoxy-proxy-authentication-credential-exposure-cve-2013-2503/
} else {
if ("content-length".equals(lcKey)) {
// save for compress decision on server side
@@ -192,6 +193,17 @@ class HTTPResponseOutputStream extends FilterOutputStream {
} else if ("content-type".equals(lcKey)) {
// save for compress decision on server side
_contentType = val;
} else if ("set-cookie".equals(lcKey)) {
String lcVal = val.toLowerCase(Locale.US);
if (lcVal.contains("domain=b32.i2p") ||
lcVal.contains("domain=.b32.i2p")) {
// Strip privacy-damaging "supercookie" for b32.i2p
// Let's presume the user agent ignores a cookie for "i2p"
// See RFC 6265 and http://publicsuffix.org/
if (_log.shouldLog(Log.INFO))
_log.info("Stripping \"" + key + ": " + val + "\" from response ");
break;
}
}
out.write((key.trim() + ": " + val.trim() + "\r\n").getBytes());
}
@@ -274,7 +286,7 @@ class HTTPResponseOutputStream extends FilterOutputStream {
while ( (read = _in.read(buf)) != -1) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Read " + read + " and writing it to the browser/streams");
; _out.write(buf, 0, read);
_out.write(buf, 0, read);
_out.flush();
written += read;
}

View File

@@ -694,7 +694,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
public void runClient(String args[], Logging l) {
boolean isShared = true;
if (args.length >= 3)
isShared = Boolean.valueOf(args[2].trim()).booleanValue();
isShared = Boolean.parseBoolean(args[2].trim());
if (args.length >= 2) {
int portNum = -1;
try {
@@ -717,7 +717,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
addtask(task);
notifyEvent("clientTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
String msg = "Invalid I2PTunnel configuration to create an HTTP Proxy connecting to the router at " + host + ':'+ port +
String msg = "Invalid I2PTunnel configuration to create a standard client tunnel connecting to the router at " + host + ':'+ port +
" and listening on " + listenHost + ':' + portNum;
_log.error(getPrefix() + msg, iae);
l.log(msg);
@@ -766,7 +766,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
String proxy = "";
boolean isShared = true;
if (args.length > 1) {
if (Boolean.valueOf(args[1].trim()).booleanValue()) {
if (Boolean.parseBoolean(args[1].trim())) {
isShared = true;
if (args.length == 3)
proxy = args[2];
@@ -835,7 +835,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
String proxy = "";
boolean isShared = true;
if (args.length > 1) {
if (Boolean.valueOf(args[1].trim()).booleanValue()) {
if (Boolean.parseBoolean(args[1].trim())) {
isShared = true;
if (args.length == 3)
proxy = args[2];
@@ -906,7 +906,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
boolean isShared = true;
if (args.length > 2) {
if (Boolean.valueOf(args[2].trim()).booleanValue()) {
if (Boolean.parseBoolean(args[2].trim())) {
isShared = true;
} else if ("false".equalsIgnoreCase(args[2].trim())) {
_log.warn("args[2] == [" + args[2] + "] and rejected explicitly");
@@ -973,7 +973,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
boolean isShared = false;
if (args.length > 1)
isShared = Boolean.valueOf(args[1].trim()).booleanValue();
isShared = Boolean.parseBoolean(args[1].trim());
ownDest = !isShared;
try {
@@ -1017,7 +1017,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
boolean isShared = false;
if (args.length == 2)
isShared = Boolean.valueOf(args[1].trim()).booleanValue();
isShared = Boolean.parseBoolean(args[1].trim());
ownDest = !isShared;
String privateKeyFile = null;

View File

@@ -190,11 +190,11 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
// no need to load the netDb with leaseSets for destinations that will never
// be looked up
boolean dccEnabled = (this instanceof I2PTunnelIRCClient) &&
Boolean.valueOf(tunnel.getClientOptions().getProperty(I2PTunnelIRCClient.PROP_DCC)).booleanValue();
Boolean.parseBoolean(tunnel.getClientOptions().getProperty(I2PTunnelIRCClient.PROP_DCC));
if (!dccEnabled)
tunnel.getClientOptions().setProperty("i2cp.dontPublishLeaseSet", "true");
boolean openNow = !Boolean.valueOf(tunnel.getClientOptions().getProperty("i2cp.delayOpen")).booleanValue();
boolean openNow = !Boolean.parseBoolean(tunnel.getClientOptions().getProperty("i2cp.delayOpen"));
if (openNow) {
while (sockMgr == null) {
verifySocketManager();
@@ -258,8 +258,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
if (sess == null) {
newManager = true;
} else if (sess.isClosed() &&
Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.closeOnIdle")).booleanValue() &&
Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.newDestOnResume")).booleanValue()) {
Boolean.parseBoolean(getTunnel().getClientOptions().getProperty("i2cp.closeOnIdle")) &&
Boolean.parseBoolean(getTunnel().getClientOptions().getProperty("i2cp.newDestOnResume"))) {
// build a new socket manager and a new dest if the session is closed.
getTunnel().removeSession(sess);
if (_log.shouldLog(Log.WARN))

View File

@@ -13,6 +13,7 @@ import java.util.Locale;
import java.util.Properties;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketOptions;
@@ -20,7 +21,6 @@ import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.util.EventDispatcher;
import net.i2p.util.FileUtil;
import net.i2p.util.Log;
import net.i2p.util.PortMapper;
@@ -58,6 +58,8 @@ import net.i2p.util.PortMapper;
*/
public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements Runnable {
public static final String AUTH_REALM = "I2P SSL Proxy";
private final static byte[] ERR_DESTINATION_UNKNOWN =
("HTTP/1.1 503 Service Unavailable\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
@@ -89,17 +91,6 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>")
.getBytes();
private final static byte[] ERR_AUTH =
("HTTP/1.1 407 Proxy Authentication Required\r\n"+
"Content-Type: text/html; charset=UTF-8\r\n"+
"Cache-control: no-cache\r\n"+
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.5\r\n" + // try to get a UTF-8-encoded response back for the password
"Proxy-Authenticate: Basic realm=\"I2P SSL Proxy\"\r\n" +
"\r\n"+
"<html><body><H1>I2P ERROR: PROXY AUTHENTICATION REQUIRED</H1>"+
"This proxy is configured to require authentication.<BR>")
.getBytes();
private final static byte[] SUCCESS_RESPONSE =
("HTTP/1.1 200 Connection Established\r\n"+
"Proxy-agent: I2P\r\n"+
@@ -165,6 +156,11 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
return super.close(forced);
}
/** @since 0.9.4 */
protected String getRealm() {
return AUTH_REALM;
}
protected void clientConnectionRun(Socket s) {
InputStream in = null;
OutputStream out = null;
@@ -237,10 +233,10 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
_log.debug(getPrefix(requestId) + "REST :" + restofline + ":");
_log.debug(getPrefix(requestId) + "DEST :" + destination + ":");
}
} else if (line.toLowerCase(Locale.US).startsWith("proxy-authorization: basic ")) {
} else if (line.toLowerCase(Locale.US).startsWith("proxy-authorization: ")) {
// strip Proxy-Authenticate from the response in HTTPResponseOutputStream
// save for auth check below
authorization = line.substring(27); // "proxy-authorization: basic ".length()
authorization = line.substring(21); // "proxy-authorization: ".length()
line = null;
} else if (line.length() > 0) {
// Additional lines - shouldn't be too many. Firefox sends:
@@ -253,7 +249,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
line = null;
} else {
// Add Proxy-Authentication header for next hop (outproxy)
if (usingWWWProxy && Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_AUTH)).booleanValue()) {
if (usingWWWProxy && Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_AUTH))) {
// specific for this proxy
String user = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_USER_PREFIX + currentProxy);
String pw = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_PW_PREFIX + currentProxy);
@@ -281,30 +277,26 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
}
// Authorization
if (!authorize(s, requestId, authorization)) {
AuthResult result = authorize(s, requestId, method, authorization);
if (result != AuthResult.AUTH_GOOD) {
if (_log.shouldLog(Log.WARN)) {
if (authorization != null)
_log.warn(getPrefix(requestId) + "Auth failed, sending 407 again");
else
_log.warn(getPrefix(requestId) + "Auth required, sending 407");
}
writeErrorMessage(ERR_AUTH, out);
out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes());
s.close();
return;
}
Destination clientDest = _context.namingService().lookup(destination);
if (clientDest == null) {
String str;
byte[] header;
if (usingWWWProxy)
str = FileUtil.readTextFile((new File(_errorDir, "dnfp-header.ht")).getAbsolutePath(), 100, true);
header = getErrorPage("dnfp-header.ht", ERR_DESTINATION_UNKNOWN);
else
str = FileUtil.readTextFile((new File(_errorDir, "dnfh-header.ht")).getAbsolutePath(), 100, true);
if (str != null)
header = str.getBytes();
else
header = ERR_DESTINATION_UNKNOWN;
header = getErrorPage("dnfh-header.ht", ERR_DESTINATION_UNKNOWN);
writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination);
s.close();
return;
@@ -341,12 +333,13 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
}
private static class OnTimeout implements Runnable {
private Socket _socket;
private OutputStream _out;
private String _target;
private boolean _usingProxy;
private String _wwwProxy;
private long _requestId;
private final Socket _socket;
private final OutputStream _out;
private final String _target;
private final boolean _usingProxy;
private final String _wwwProxy;
private final long _requestId;
public OnTimeout(Socket s, OutputStream out, String target, boolean usingProxy, String wwwProxy, long id) {
_socket = s;
_out = out;
@@ -355,6 +348,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
_wwwProxy = wwwProxy;
_requestId = id;
}
public void run() {
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Timeout occured requesting " + _target);
@@ -391,17 +385,12 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
boolean usingWWWProxy, String wwwProxy, long requestId) {
if (out == null)
return;
byte[] header;
if (usingWWWProxy)
header = getErrorPage(I2PAppContext.getGlobalContext(), "dnfp-header.ht", ERR_DESTINATION_UNKNOWN);
else
header = getErrorPage(I2PAppContext.getGlobalContext(), "dnf-header.ht", ERR_DESTINATION_UNKNOWN);
try {
String str;
byte[] header;
if (usingWWWProxy)
str = FileUtil.readTextFile((new File(_errorDir, "dnfp-header.ht")).getAbsolutePath(), 100, true);
else
str = FileUtil.readTextFile((new File(_errorDir, "dnf-header.ht")).getAbsolutePath(), 100, true);
if (str != null)
header = str.getBytes();
else
header = ERR_DESTINATION_UNKNOWN;
writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy);
} catch (IOException ioe) {}
}

View File

@@ -1,17 +1,9 @@
/**
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* WTFPL
* Version 2, December 2004
*
* Copyright (C) sponge
* Planet Earth
* Everyone is permitted to copy and distribute verbatim or modified
* copies of this license document, and changing it is allowed as long
* as the name is changed.
*
* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
* TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
*
* 0. You just DO WHAT THE FUCK YOU WANT TO.
*
* See...
*
@@ -19,9 +11,8 @@
* and
* http://en.wikipedia.org/wiki/WTFPL
*
* ...for any additional details and liscense questions.
* ...for any additional details and license questions.
*/
package net.i2p.i2ptunnel;
// import java.util.ArrayList;

View File

@@ -3,9 +3,7 @@
*/
package net.i2p.i2ptunnel;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -73,10 +71,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
* via address helper links
*/
private final ConcurrentHashMap<String, String> addressHelpers = new ConcurrentHashMap(8);
/**
* Used to protect actions via http://proxy.i2p/
*/
private final String _proxyNonce;
public static final String AUTH_REALM = "I2P HTTP Proxy";
/**
* These are backups if the xxx.ht error page is missing.
*/
@@ -160,6 +162,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"<html><body><H1>I2P ERROR: NON-HTTP PROTOCOL</H1>" +
"The request uses a bad protocol. " +
"The I2P HTTP Proxy supports http:// requests ONLY. Other protocols such as https:// and ftp:// are not allowed.<BR>").getBytes();
private final static byte[] ERR_BAD_URI =
("HTTP/1.1 403 Bad URI\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"\r\n" +
"<html><body><H1>I2P ERROR: INVALID REQUEST URI</H1>" +
"The request URI is invalid, and probably contains illegal characters. " +
"If you clicked e.g. a forum link, check the end of the URI for any characters the browser has mistakenly added on.<BR>").getBytes();
private final static byte[] ERR_LOCALHOST =
("HTTP/1.1 403 Access Denied\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
@@ -167,15 +177,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"\r\n" +
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>" +
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>").getBytes();
private final static byte[] ERR_AUTH =
("HTTP/1.1 407 Proxy Authentication Required\r\n" +
"Content-Type: text/html; charset=UTF-8\r\n" +
"Cache-control: no-cache\r\n" +
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.5\r\n" + // try to get a UTF-8-encoded response back for the password
"Proxy-Authenticate: Basic realm=\"I2P HTTP Proxy\"\r\n" +
"\r\n" +
"<html><body><H1>I2P ERROR: PROXY AUTHENTICATION REQUIRED</H1>" +
"This proxy is configured to require authentication.<BR>").getBytes();
/**
* This constructor always starts the tunnel (ignoring the i2cp.delayOpen option).
@@ -280,6 +281,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
*/
@Override
public void startRunning() {
// following are for HTTPResponseOutputStream
_context.statManager().createRateStat("i2ptunnel.httpCompressionRatio", "ratio of compressed size to decompressed size after transfer", "I2PTunnel", new long[] { 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.httpCompressed", "compressed size transferred", "I2PTunnel", new long[] { 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.httpExpanded", "size transferred after expansion", "I2PTunnel", new long[] { 60*60*1000 });
super.startRunning();
this.isr = new InternalSocketRunner(this);
_context.portMapper().register(PortMapper.SVC_HTTP_PROXY, getLocalPort());
@@ -300,6 +305,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
return rv;
}
/** @since 0.9.4 */
protected String getRealm() {
return AUTH_REALM;
}
private static final String HELPER_PARAM = "i2paddresshelper";
public static final String LOCAL_SERVER = "proxy.i2p";
private static final boolean DEFAULT_GZIP = true;
@@ -337,6 +348,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
String userAgent = null;
String authorization = null;
int remotePort = 0;
String referer = null;
while((line = reader.readLine(method)) != null) {
line = line.trim();
if(_log.shouldLog(Log.DEBUG)) {
@@ -424,7 +436,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Bad request [" + request + "]", use);
}
break;
if(out != null) {
out.write(getErrorPage("baduri", ERR_BAD_URI));
writeFooter(out);
}
s.close();
return;
}
method = params[0];
String protocolVersion = params[2];
@@ -521,7 +538,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
// Try to find an address helper in the query
String[] helperStrings = removeHelper(query);
if(helperStrings != null &&
!Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER)).booleanValue()) {
!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
query = helperStrings[0];
if(query.equals("")) {
query = null;
@@ -736,7 +753,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
} else if(lowercaseLine.startsWith("user-agent: ")) {
// save for deciding whether to offer address book form
userAgent = lowercaseLine.substring(12);
if(!Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_USER_AGENT)).booleanValue()) {
if(!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_USER_AGENT))) {
line = null;
continue;
}
@@ -745,14 +762,17 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
// browser to browser
line = null;
continue;
} else if(lowercaseLine.startsWith("referer: ") &&
!Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_REFERER)).booleanValue()) {
// Shouldn't we be more specific, like accepting in-site referers ?
//line = "Referer: i2p";
line = null;
continue; // completely strip the line
} else if (lowercaseLine.startsWith("referer: ")) {
// save for address helper form below
referer = line.substring(9);
if (!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_REFERER))) {
// Shouldn't we be more specific, like accepting in-site referers ?
//line = "Referer: i2p";
line = null;
continue; // completely strip the line
}
} else if(lowercaseLine.startsWith("via: ") &&
!Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_VIA)).booleanValue()) {
!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_VIA))) {
//line = "Via: i2p";
line = null;
continue; // completely strip the line
@@ -769,10 +789,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
// hop-by-hop header, and we definitely want to block Windows NTLM after a far-end 407.
// Response to far-end shouldn't happen, as we
// strip Proxy-Authenticate from the response in HTTPResponseOutputStream
if(lowercaseLine.startsWith("proxy-authorization: basic ")) // save for auth check below
{
authorization = line.substring(27); // "proxy-authorization: basic ".length()
}
authorization = line.substring(21); // "proxy-authorization: ".length()
line = null;
continue;
} else if(lowercaseLine.startsWith("icy")) {
@@ -786,7 +803,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
String ok = getTunnel().getClientOptions().getProperty("i2ptunnel.gzip");
boolean gzip = DEFAULT_GZIP;
if(ok != null) {
gzip = Boolean.valueOf(ok).booleanValue();
gzip = Boolean.parseBoolean(ok);
}
if(gzip && !usingInternalServer) {
// according to rfc2616 s14.3, this *should* force identity, even if
@@ -796,7 +813,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
newRequest.append("X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n");
}
if(!shout) {
if(!Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_USER_AGENT)).booleanValue()) {
if(!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_USER_AGENT))) {
// let's not advertise to external sites that we are from I2P
if(usingWWWProxy) {
newRequest.append("User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6\r\n");
@@ -806,7 +823,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
}
// Add Proxy-Authentication header for next hop (outproxy)
if(usingWWWProxy && Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_AUTH)).booleanValue()) {
if(usingWWWProxy && Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_AUTH))) {
// specific for this proxy
String user = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_USER_PREFIX + currentProxy);
String pw = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_PW_PREFIX + currentProxy);
@@ -850,7 +867,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
// Authorization
if(!authorize(s, requestId, authorization)) {
AuthResult result = authorize(s, requestId, method, authorization);
if (result != AuthResult.AUTH_GOOD) {
if(_log.shouldLog(Log.WARN)) {
if(authorization != null) {
_log.warn(getPrefix(requestId) + "Auth failed, sending 407 again");
@@ -858,7 +876,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
_log.warn(getPrefix(requestId) + "Auth required, sending 407");
}
}
out.write(getErrorPage("auth", ERR_AUTH));
out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes());
writeFooter(out);
s.close();
return;
@@ -869,7 +887,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(usingInternalServer) {
// disable the add form if address helper is disabled
if(internalPath.equals("/add") &&
Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER)).booleanValue()) {
Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
out.write(ERR_HELPER_DISABLED);
} else {
LocalHTTPServer.serveLocalFile(out, method, internalPath, internalRawQuery, _proxyNonce);
@@ -949,8 +967,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
// Don't do this for eepget, which uses a user-agent of "Wget"
if(ahelperNew && "GET".equals(method) &&
(userAgent == null || !userAgent.startsWith("Wget")) &&
!Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER)).booleanValue()) {
writeHelperSaveForm(out, destination, ahelperKey, targetRequest);
!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
writeHelperSaveForm(out, destination, ahelperKey, targetRequest, referer);
s.close();
return;
}
@@ -1014,7 +1032,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
/** @since 0.8.7 */
private void writeHelperSaveForm(OutputStream out, String destination, String ahelperKey, String targetRequest) throws IOException {
private void writeHelperSaveForm(OutputStream out, String destination, String ahelperKey,
String targetRequest, String referer) throws IOException {
if(out == null) {
return;
}
@@ -1045,6 +1064,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
out.write(("<br><button type=\"submit\" name=\"master\" value=\"master\">" + _("Save {0} to master address book and continue to eepsite", destination) + "</button><br>\n").getBytes("UTF-8"));
out.write(("<button type=\"submit\" name=\"private\" value=\"private\">" + _("Save {0} to private address book and continue to eepsite", destination) + "</button>\n").getBytes("UTF-8"));
}
// Firefox (and others?) don't send referer to meta refresh target, which is
// what the jump servers use, so this isn't that useful.
if (referer != null)
out.write(("<input type=\"hidden\" name=\"referer\" value=\"" + referer + "\">\n").getBytes("UTF-8"));
out.write(("<input type=\"hidden\" name=\"url\" value=\"" + targetRequest + "\">\n" +
"</form></div></div>").getBytes());
writeFooter(out);
@@ -1095,61 +1118,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
return Base32.encode(_dest.calculateHash().getData()) + ".b32.i2p";
}
/**
* foo => errordir/foo-header_xx.ht for lang xx, or errordir/foo-header.ht,
* or the backup byte array on fail.
*
* .ht files must be UTF-8 encoded and use \r\n terminators so the
* HTTP headers are conformant.
* We can't use FileUtil.readFile() because it strips \r
*
* @return non-null
*/
private byte[] getErrorPage(String base, byte[] backup) {
return getErrorPage(_context, base, backup);
}
private static byte[] getErrorPage(I2PAppContext ctx, String base, byte[] backup) {
File errorDir = new File(ctx.getBaseDir(), "docs");
String lang = ctx.getProperty("routerconsole.lang", Locale.getDefault().getLanguage());
if(lang != null && lang.length() > 0 && !lang.equals("en")) {
File file = new File(errorDir, base + "-header_" + lang + ".ht");
try {
return readFile(file);
} catch(IOException ioe) {
// try the english version now
}
}
File file = new File(errorDir, base + "-header.ht");
try {
return readFile(file);
} catch(IOException ioe) {
return backup;
}
}
private static byte[] readFile(File file) throws IOException {
FileInputStream fis = null;
byte[] buf = new byte[512];
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
try {
int len = 0;
fis = new FileInputStream(file);
while((len = fis.read(buf)) > 0) {
baos.write(buf, 0, len);
}
return baos.toByteArray();
} finally {
try {
if(fis != null) {
fis.close();
}
} catch(IOException foo) {
}
}
// we won't ever get here
}
/**
* Public only for LocalHTTPServer, not for general use
*/
@@ -1163,12 +1131,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
private static class OnTimeout implements Runnable {
private Socket _socket;
private OutputStream _out;
private String _target;
private boolean _usingProxy;
private String _wwwProxy;
private long _requestId;
private final Socket _socket;
private final OutputStream _out;
private final String _target;
private final boolean _usingProxy;
private final String _wwwProxy;
private final long _requestId;
public OnTimeout(Socket s, OutputStream out, String target, boolean usingProxy, String wwwProxy, long id) {
_socket = s;

View File

@@ -3,19 +3,30 @@
*/
package net.i2p.i2ptunnel;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.ArrayList;
import java.io.File;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.I2PAppContext;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.util.EventDispatcher;
import net.i2p.util.InternalSocket;
import net.i2p.util.Log;
import net.i2p.util.PasswordManager;
/**
* Common things for HTTPClient and ConnectClient
@@ -25,6 +36,26 @@ import net.i2p.util.Log;
*/
public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implements Runnable {
private static final int PROXYNONCE_BYTES = 8;
private static final int MD5_BYTES = 16;
/** 24 */
private static final int NONCE_BYTES = DataHelper.DATE_LENGTH + MD5_BYTES;
private static final long MAX_NONCE_AGE = 60*60*1000L;
private static final int MAX_NONCE_COUNT = 1024;
private static final String ERR_AUTH1 =
"HTTP/1.1 407 Proxy Authentication Required\r\n" +
"Content-Type: text/html; charset=UTF-8\r\n" +
"Cache-control: no-cache\r\n" +
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.5\r\n" + // try to get a UTF-8-encoded response back for the password
"Proxy-Authenticate: ";
// put the auth type and realm in between
private static final String ERR_AUTH2 =
"\r\n" +
"\r\n" +
"<html><body><H1>I2P ERROR: PROXY AUTHENTICATION REQUIRED</H1>" +
"This proxy is configured to require authentication.";
protected final List<String> _proxyList;
protected final static byte[] ERR_NO_OUTPROXY =
@@ -40,7 +71,9 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
/** used to assign unique IDs to the threads / clients. no logic or functionality */
protected static volatile long __clientId = 0;
protected static final File _errorDir = new File(I2PAppContext.getGlobalContext().getBaseDir(), "docs");
private final byte[] _proxyNonce;
private final ConcurrentHashMap<String, NonceInfo> _nonces;
private final AtomicInteger _nonceCleanCounter = new AtomicInteger();
protected String getPrefix(long requestId) { return "Client[" + _clientId + "/" + requestId + "]: "; }
@@ -63,6 +96,9 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
I2PTunnel tunnel) throws IllegalArgumentException {
super(localPort, ownDest, l, notifyThis, handlerName, tunnel);
_proxyList = new ArrayList(4);
_proxyNonce = new byte[PROXYNONCE_BYTES];
_context.random().nextBytes(_proxyNonce);
_nonces = new ConcurrentHashMap();
}
/**
@@ -76,8 +112,13 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
throws IllegalArgumentException {
super(localPort, l, sktMgr, tunnel, notifyThis, clientId);
_proxyList = new ArrayList(4);
_proxyNonce = new byte[PROXYNONCE_BYTES];
_context.random().nextBytes(_proxyNonce);
_nonces = new ConcurrentHashMap();
}
//////// Authorization stuff
/** all auth @since 0.8.2 */
public static final String PROP_AUTH = "proxyAuth";
public static final String PROP_USER = "proxyUsername";
@@ -90,68 +131,410 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
/** passwords for specific outproxies may be added with outproxyUsername.fooproxy.i2p=user and outproxyPassword.fooproxy.i2p=pw */
public static final String PROP_OUTPROXY_USER_PREFIX = PROP_OUTPROXY_USER + '.';
public static final String PROP_OUTPROXY_PW_PREFIX = PROP_OUTPROXY_PW + '.';
/** new style MD5 auth */
public static final String PROP_PROXY_DIGEST_PREFIX = "proxy.auth.";
public static final String PROP_PROXY_DIGEST_SUFFIX = ".md5";
public static final String BASIC_AUTH = "basic";
public static final String DIGEST_AUTH = "digest";
protected abstract String getRealm();
protected enum AuthResult {AUTH_BAD_REQ, AUTH_BAD, AUTH_STALE, AUTH_GOOD}
/**
* @param authorization may be null
* @return success
* @since 0.9.6
*/
protected boolean authorize(Socket s, long requestId, String authorization) {
// Authorization
// Ref: RFC 2617
// If the socket is an InternalSocket, no auth required.
String authRequired = getTunnel().getClientOptions().getProperty(PROP_AUTH);
if (Boolean.valueOf(authRequired).booleanValue() ||
(authRequired != null && "basic".equals(authRequired.toLowerCase(Locale.US)))) {
if (s instanceof InternalSocket) {
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix(requestId) + "Internal access, no auth required");
return true;
} else if (authorization != null) {
// hmm safeDecode(foo, true) to use standard alphabet is private in Base64
byte[] decoded = Base64.decode(authorization.replace("/", "~").replace("+", "="));
if (decoded != null) {
// We send Accept-Charset: UTF-8 in the 407 so hopefully it comes back that way inside the B64 ?
try {
String dec = new String(decoded, "UTF-8");
String[] parts = dec.split(":");
String user = parts[0];
String pw = parts[1];
// first try pw for that user
String configPW = getTunnel().getClientOptions().getProperty(PROP_PW_PREFIX + user);
if (configPW == null) {
// if not, look at default user and pw
String configUser = getTunnel().getClientOptions().getProperty(PROP_USER);
if (user.equals(configUser))
configPW = getTunnel().getClientOptions().getProperty(PROP_PW);
}
if (configPW != null) {
if (pw.equals(configPW)) {
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix(requestId) + "Good auth - user: " + user + " pw: " + pw);
return true;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth, pw mismatch - user: " + user + " pw: " + pw + " expected: " + configPW);
}
} else {
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth, no stored pw for user: " + user + " pw: " + pw);
}
} catch (UnsupportedEncodingException uee) {
_log.error(getPrefix(requestId) + "No UTF-8 support? B64: " + authorization, uee);
} catch (ArrayIndexOutOfBoundsException aioobe) {
// no ':' in response
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization, aioobe);
}
} else {
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization);
}
private static class NonceInfo {
private final long expires;
private final BitSet counts;
public NonceInfo(long exp) {
expires = exp;
counts = new BitSet(MAX_NONCE_COUNT);
}
public long getExpires() {
return expires;
}
public AuthResult isValid(int nc) {
if (nc <= 0)
return AuthResult.AUTH_BAD;
if (nc >= MAX_NONCE_COUNT)
return AuthResult.AUTH_STALE;
synchronized(counts) {
if (counts.get(nc))
return AuthResult.AUTH_BAD;
counts.set(nc);
}
return false;
} else {
return true;
return AuthResult.AUTH_GOOD;
}
}
/**
* @since 0.9.4
*/
protected boolean isDigestAuthRequired() {
String authRequired = getTunnel().getClientOptions().getProperty(PROP_AUTH);
if (authRequired == null)
return false;
return authRequired.toLowerCase(Locale.US).equals("digest");
}
/**
* Authorization
* Ref: RFC 2617
* If the socket is an InternalSocket, no auth required.
*
* @param method GET, POST, etc.
* @param authorization may be null, the full auth line e.g. "Basic lskjlksjf"
* @return success
*/
protected AuthResult authorize(Socket s, long requestId, String method, String authorization) {
String authRequired = getTunnel().getClientOptions().getProperty(PROP_AUTH);
if (authRequired == null)
return AuthResult.AUTH_GOOD;
authRequired = authRequired.toLowerCase(Locale.US);
if (authRequired.equals("false"))
return AuthResult.AUTH_GOOD;
if (s instanceof InternalSocket) {
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix(requestId) + "Internal access, no auth required");
return AuthResult.AUTH_GOOD;
}
if (authorization == null)
return AuthResult.AUTH_BAD;
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix(requestId) + "Auth: " + authorization);
String authLC = authorization.toLowerCase(Locale.US);
if (authRequired.equals("true") || authRequired.equals(BASIC_AUTH)) {
if (!authLC.startsWith("basic "))
return AuthResult.AUTH_BAD;
authorization = authorization.substring(6);
// hmm safeDecode(foo, true) to use standard alphabet is private in Base64
byte[] decoded = Base64.decode(authorization.replace("/", "~").replace("+", "="));
if (decoded != null) {
// We send Accept-Charset: UTF-8 in the 407 so hopefully it comes back that way inside the B64 ?
try {
String dec = new String(decoded, "UTF-8");
String[] parts = dec.split(":");
String user = parts[0];
String pw = parts[1];
// first try pw for that user
String configPW = getTunnel().getClientOptions().getProperty(PROP_PW_PREFIX + user);
if (configPW == null) {
// if not, look at default user and pw
String configUser = getTunnel().getClientOptions().getProperty(PROP_USER);
if (user.equals(configUser))
configPW = getTunnel().getClientOptions().getProperty(PROP_PW);
}
if (configPW != null) {
if (pw.equals(configPW)) {
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix(requestId) + "Good auth - user: " + user + " pw: " + pw);
return AuthResult.AUTH_GOOD;
}
}
_log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user);
} catch (UnsupportedEncodingException uee) {
_log.error(getPrefix(requestId) + "No UTF-8 support? B64: " + authorization, uee);
} catch (ArrayIndexOutOfBoundsException aioobe) {
// no ':' in response
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization, aioobe);
return AuthResult.AUTH_BAD_REQ;
}
return AuthResult.AUTH_BAD;
} else {
if (_log.shouldLog(Log.WARN))
_log.warn(getPrefix(requestId) + "Bad auth B64: " + authorization);
return AuthResult.AUTH_BAD_REQ;
}
} else if (authRequired.equals(DIGEST_AUTH)) {
if (!authLC.startsWith("digest "))
return AuthResult.AUTH_BAD;
authorization = authorization.substring(7);
Map<String, String> args = parseArgs(authorization);
AuthResult rv = validateDigest(method, args);
return rv;
} else {
_log.error("Unknown proxy authorization type configured: " + authRequired);
return AuthResult.AUTH_BAD_REQ;
}
}
/**
* Verify all of it.
* Ref: RFC 2617
* @since 0.9.4
*/
private AuthResult validateDigest(String method, Map<String, String> args) {
String user = args.get("username");
String realm = args.get("realm");
String nonce = args.get("nonce");
String qop = args.get("qop");
String uri = args.get("uri");
String cnonce = args.get("cnonce");
String nc = args.get("nc");
String response = args.get("response");
if (user == null || realm == null || nonce == null || qop == null ||
uri == null || cnonce == null || nc == null || response == null) {
if (_log.shouldLog(Log.INFO))
_log.info("Bad digest request: " + DataHelper.toString(args));
return AuthResult.AUTH_BAD_REQ;
}
// nonce check
AuthResult check = verifyNonce(nonce, nc);
if (check != AuthResult.AUTH_GOOD) {
if (_log.shouldLog(Log.INFO))
_log.info("Bad digest nonce: " + check + ' ' + DataHelper.toString(args));
return check;
}
// get H(A1) == stored password
String ha1 = getTunnel().getClientOptions().getProperty(PROP_PROXY_DIGEST_PREFIX + user +
PROP_PROXY_DIGEST_SUFFIX);
if (ha1 == null) {
_log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user);
return AuthResult.AUTH_BAD;
}
// get H(A2)
String a2 = method + ':' + uri;
String ha2 = PasswordManager.md5Hex(a2);
// response check
String kd = ha1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2;
String hkd = PasswordManager.md5Hex(kd);
if (!response.equals(hkd)) {
_log.logAlways(Log.WARN, "PROXY AUTH FAILURE: user " + user);
if (_log.shouldLog(Log.INFO))
_log.info("Bad digest auth: " + DataHelper.toString(args));
return AuthResult.AUTH_BAD;
}
if (_log.shouldLog(Log.INFO))
_log.info("Good digest auth - user: " + user);
return AuthResult.AUTH_GOOD;
}
/**
* The Base 64 of 24 bytes: (now, md5 of (now, proxy nonce))
* @since 0.9.4
*/
private String getNonce() {
byte[] b = new byte[DataHelper.DATE_LENGTH + PROXYNONCE_BYTES];
byte[] n = new byte[NONCE_BYTES];
long now = _context.clock().now();
DataHelper.toLong(b, 0, DataHelper.DATE_LENGTH, now);
System.arraycopy(_proxyNonce, 0, b, DataHelper.DATE_LENGTH, PROXYNONCE_BYTES);
System.arraycopy(b, 0, n, 0, DataHelper.DATE_LENGTH);
byte[] md5 = PasswordManager.md5Sum(b);
System.arraycopy(md5, 0, n, DataHelper.DATE_LENGTH, MD5_BYTES);
String rv = Base64.encode(n);
_nonces.putIfAbsent(rv, new NonceInfo(now + MAX_NONCE_AGE));
return rv;
}
/**
* Verify the Base 64 of 24 bytes: (now, md5 of (now, proxy nonce))
* and the nonce count.
* @param b64 nonce non-null
* @param ncs nonce count string non-null
* @since 0.9.4
*/
private AuthResult verifyNonce(String b64, String ncs) {
if (_nonceCleanCounter.incrementAndGet() % 16 == 0)
cleanNonces();
byte[] n = Base64.decode(b64);
if (n == null || n.length != NONCE_BYTES)
return AuthResult.AUTH_BAD;
long now = _context.clock().now();
long stamp = DataHelper.fromLong(n, 0, DataHelper.DATE_LENGTH);
if (now - stamp > MAX_NONCE_AGE) {
_nonces.remove(b64);
return AuthResult.AUTH_STALE;
}
NonceInfo info = _nonces.get(b64);
if (info == null)
return AuthResult.AUTH_STALE;
byte[] b = new byte[DataHelper.DATE_LENGTH + PROXYNONCE_BYTES];
System.arraycopy(n, 0, b, 0, DataHelper.DATE_LENGTH);
System.arraycopy(_proxyNonce, 0, b, DataHelper.DATE_LENGTH, PROXYNONCE_BYTES);
byte[] md5 = PasswordManager.md5Sum(b);
if (!DataHelper.eq(md5, 0, n, DataHelper.DATE_LENGTH, MD5_BYTES))
return AuthResult.AUTH_BAD;
try {
int nc = Integer.parseInt(ncs, 16);
return info.isValid(nc);
} catch (NumberFormatException nfe) {
return AuthResult.AUTH_BAD;
}
}
/**
* Remove expired nonces from map
* @since 0.9.6
*/
private void cleanNonces() {
long now = _context.clock().now();
for (Iterator<NonceInfo> iter = _nonces.values().iterator(); iter.hasNext(); ) {
NonceInfo info = iter.next();
if (info.getExpires() <= now)
iter.remove();
}
}
/**
* What to send if digest auth fails
* @since 0.9.4
*/
protected String getAuthError(boolean isStale) {
boolean isDigest = isDigestAuthRequired();
return
ERR_AUTH1 +
(isDigest ? "Digest" : "Basic") +
" realm=\"" + getRealm() + '"' +
(isDigest ? ", nonce=\"" + getNonce() + "\"," +
" algorithm=MD5," +
" qop=\"auth\"" +
(isStale ? ", stale=true" : "")
: "") +
ERR_AUTH2;
}
/**
* Modified from LoadClientAppsJob.
* All keys are mapped to lower case.
* Ref: RFC 2617
*
* @param args non-null
* @since 0.9.4
*/
private static Map<String, String> parseArgs(String args) {
Map<String, String> rv = new HashMap(8);
char data[] = args.toCharArray();
StringBuilder buf = new StringBuilder(32);
boolean isQuoted = false;
String key = null;
for (int i = 0; i < data.length; i++) {
switch (data[i]) {
case '\"':
if (isQuoted) {
// keys never quoted
if (key != null) {
rv.put(key, buf.toString().trim());
key = null;
}
buf.setLength(0);
}
isQuoted = !isQuoted;
break;
case ' ':
case '\r':
case '\n':
case '\t':
case ',':
// whitespace - if we're in a quoted section, keep this as part of the quote,
// otherwise use it as a delim
if (isQuoted) {
buf.append(data[i]);
} else {
if (key != null) {
rv.put(key, buf.toString().trim());
key = null;
}
buf.setLength(0);
}
break;
case '=':
if (isQuoted) {
buf.append(data[i]);
} else {
key = buf.toString().trim().toLowerCase(Locale.US);
buf.setLength(0);
}
break;
default:
buf.append(data[i]);
break;
}
}
if (key != null)
rv.put(key, buf.toString().trim());
return rv;
}
//////// Error page stuff
/**
* foo => errordir/foo-header_xx.ht for lang xx, or errordir/foo-header.ht,
* or the backup byte array on fail.
*
* .ht files must be UTF-8 encoded and use \r\n terminators so the
* HTTP headers are conformant.
* We can't use FileUtil.readFile() because it strips \r
*
* @return non-null
* @since 0.9.4 moved from I2PTunnelHTTPClient
*/
protected byte[] getErrorPage(String base, byte[] backup) {
return getErrorPage(_context, base, backup);
}
/**
* foo => errordir/foo-header_xx.ht for lang xx, or errordir/foo-header.ht,
* or the backup byte array on fail.
*
* .ht files must be UTF-8 encoded and use \r\n terminators so the
* HTTP headers are conformant.
* We can't use FileUtil.readFile() because it strips \r
*
* @return non-null
* @since 0.9.4 moved from I2PTunnelHTTPClient
*/
protected static byte[] getErrorPage(I2PAppContext ctx, String base, byte[] backup) {
File errorDir = new File(ctx.getBaseDir(), "docs");
String lang = ctx.getProperty("routerconsole.lang", Locale.getDefault().getLanguage());
if(lang != null && lang.length() > 0 && !lang.equals("en")) {
File file = new File(errorDir, base + "-header_" + lang + ".ht");
try {
return readFile(file);
} catch(IOException ioe) {
// try the english version now
}
}
File file = new File(errorDir, base + "-header.ht");
try {
return readFile(file);
} catch(IOException ioe) {
return backup;
}
}
/**
* @since 0.9.4 moved from I2PTunnelHTTPClient
*/
private static byte[] readFile(File file) throws IOException {
FileInputStream fis = null;
byte[] buf = new byte[2048];
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
try {
int len = 0;
fis = new FileInputStream(file);
while((len = fis.read(buf)) > 0) {
baos.write(buf, 0, len);
}
return baos.toByteArray();
} finally {
try {
if(fis != null) {
fis.close();
}
} catch(IOException foo) {
}
}
// we won't ever get here
}
}

View File

@@ -45,7 +45,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
private static final String[] CLIENT_SKIPHEADERS = {HASH_HEADER, DEST64_HEADER, DEST32_HEADER};
private static final String SERVER_HEADER = "Server";
private static final String[] SERVER_SKIPHEADERS = {SERVER_HEADER};
private static final long HEADER_TIMEOUT = 60*1000;
private static final long HEADER_TIMEOUT = 15*1000;
private static final long TOTAL_HEADER_TIMEOUT = 2 * HEADER_TIMEOUT;
private static final long START_INTERVAL = (60 * 1000) * 3;
private long _startedOn = 0L;
@@ -154,7 +155,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
boolean allowGZIP = true;
if (opts != null) {
String val = opts.getProperty("i2ptunnel.gzip");
if ( (val != null) && (!Boolean.valueOf(val).booleanValue()) )
if ( (val != null) && (!Boolean.parseBoolean(val)) )
allowGZIP = false;
}
if (_log.shouldLog(Log.INFO))
@@ -492,7 +493,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
}
}
protected static Map<String, List<String>> readHeaders(InputStream in, StringBuilder command, String[] skipHeaders, I2PAppContext ctx) throws IOException {
protected static Map<String, List<String>> readHeaders(InputStream in, StringBuilder command,
String[] skipHeaders, I2PAppContext ctx) throws IOException {
HashMap<String, List<String>> headers = new HashMap<String, List<String>>();
StringBuilder buf = new StringBuilder(128);
@@ -516,6 +518,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
if (trimmed > 0)
ctx.statManager().addRateData("i2ptunnel.httpNullWorkaround", trimmed, 0);
// slowloris / darkloris
long expire = ctx.clock().now() + TOTAL_HEADER_TIMEOUT;
int i = 0;
while (true) {
if (++i > MAX_HEADERS)
@@ -528,6 +532,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
// end of headers reached
return headers;
} else {
if (ctx.clock().now() > expire)
throw new IOException("Headers took too long [" + buf.toString() + "]");
int split = buf.indexOf(":");
if (split <= 0) throw new IOException("Invalid HTTP header, missing colon [" + buf.toString() + "]");
String name = buf.substring(0, split).trim();

View File

@@ -87,7 +87,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
setName("IRC Client on " + tunnel.listenHost + ':' + localPort);
_dccEnabled = Boolean.valueOf(tunnel.getClientOptions().getProperty(PROP_DCC)).booleanValue();
_dccEnabled = Boolean.parseBoolean(tunnel.getClientOptions().getProperty(PROP_DCC));
// TODO add some prudent tunnel options (or is it too late?)
startRunning();

View File

@@ -62,7 +62,8 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
public static final String PROP_WEBIRC_SPOOF_IP_DEFAULT="127.0.0.1";
public static final String PROP_HOSTNAME="ircserver.fakeHostname";
public static final String PROP_HOSTNAME_DEFAULT="%f.b32.i2p";
private static final long HEADER_TIMEOUT = 60*1000;
private static final long HEADER_TIMEOUT = 15*1000;
private static final long TOTAL_HEADER_TIMEOUT = 2 * HEADER_TIMEOUT;
private final static byte[] ERR_UNAVAILABLE =
(":ircserver.i2p 499 you :" +
@@ -71,6 +72,11 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
"\r\n")
.getBytes();
private static final String[] BAD_PROTOCOLS = {
"GET ", "HEAD ", "POST ", "GNUTELLA CONNECT", "\023BitTorrent protocol"
};
/**
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
@@ -78,11 +84,9 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
public I2PTunnelIRCServer(InetAddress host, int port, File privkey, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
super(host, port, privkey, privkeyname, l, notifyThis, tunnel);
initCloak(tunnel);
}
/** generate a random 32 bytes, or the hash of the passphrase */
private void initCloak(I2PTunnel tunnel) {
// generate a random 32 bytes, or the hash of the passphrase
// get the properties of this server-tunnel
Properties opts = tunnel.getClientOptions();
@@ -188,12 +192,22 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
StringBuilder buf = new StringBuilder(128);
int lineCount = 0;
// slowloris / darkloris
long expire = System.currentTimeMillis() + TOTAL_HEADER_TIMEOUT;
while (true) {
String s = DataHelper.readLine(in);
if (s == null)
throw new IOException("EOF reached before the end of the headers [" + buf.toString() + "]");
if (lineCount == 0) {
for (int i = 0; i < BAD_PROTOCOLS.length; i++) {
if (s.startsWith(BAD_PROTOCOLS[i]))
throw new IOException("Bad protocol " + BAD_PROTOCOLS[i]);
}
}
if (++lineCount > 10)
throw new IOException("Too many lines before USER or SERVER, giving up");
if (System.currentTimeMillis() > expire)
throw new IOException("Headers took too long [" + buf.toString() + "]");
s = s.trim();
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Got line: " + s);
@@ -231,9 +245,9 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
return buf.toString();
}
private byte[] cloakKey; // 32 bytes of stuff to scramble the dest with
private String hostname;
private String method;
private String webircPassword;
private String webircSpoofIP;
private final byte[] cloakKey; // 32 bytes of stuff to scramble the dest with
private final String hostname;
private final String method;
private final String webircPassword;
private final String webircSpoofIP;
}

View File

@@ -49,8 +49,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
protected Logging l;
private static final long DEFAULT_READ_TIMEOUT = -1; // 3*60*1000;
/** default timeout to 3 minutes - override if desired */
private static final long DEFAULT_READ_TIMEOUT = 5*60*1000;
/** default timeout to 5 minutes - override if desired */
protected long readTimeout = DEFAULT_READ_TIMEOUT;
/** do we use threads? default true (ignored for standard servers, always false) */
@@ -191,7 +191,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
if (_usePool) {
String usePool = getTunnel().getClientOptions().getProperty(PROP_USE_POOL);
if (usePool != null)
_usePool = Boolean.valueOf(usePool).booleanValue();
_usePool = Boolean.parseBoolean(usePool);
else
_usePool = DEFAULT_USE_POOL;
}
@@ -207,7 +207,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
if (sockMgr == null) {
// try to make this error sensible as it will happen...
String msg = "Unable to connect to the router at " + getTunnel().host + ':' + portNum +
" and build tunnels for the server at " + getTunnel().listenHost + ':' + port;
" and build tunnels for the server at " + host.getHostAddress() + ':' + port;
if (++retries < MAX_RETRIES) {
this.l.log(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds");
_log.error(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds");
@@ -223,7 +223,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
sockMgr.setName("Server");
getTunnel().addSession(sockMgr.getSession());
l.log("Tunnels ready for server at " + getTunnel().listenHost + ':' + port);
l.log("Tunnels ready for server at " + host.getHostAddress() + ':' + port);
notifyEvent("openServerResult", "ok");
open = true;
}

View File

@@ -19,8 +19,10 @@ import net.i2p.client.I2PSession;
import net.i2p.data.Base32;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.socks.I2PSOCKSTunnel;
import net.i2p.util.FileUtil;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.SecureFile;
import net.i2p.util.SecureFileOutputStream;
/**
@@ -43,6 +45,8 @@ public class TunnelController implements Logging {
private boolean _running;
private boolean _starting;
public static final String KEY_BACKUP_DIR = "i2ptunnel-keyBackup";
/**
* Create a new controller for a tunnel out of the specific config options.
* The config may contain a large number of options - only ones that begin in
@@ -102,8 +106,17 @@ public class TunnelController implements Logging {
Destination dest = client.createDestination(fos);
String destStr = dest.toBase64();
log("Private key created and saved in " + keyFile.getAbsolutePath());
log("You should backup this file in a secure place.");
log("New destination: " + destStr);
log("Base32: " + Base32.encode(dest.calculateHash().getData()) + ".b32.i2p");
String b32 = Base32.encode(dest.calculateHash().getData()) + ".b32.i2p";
log("Base32: " + b32);
File backupDir = new SecureFile(I2PAppContext.getGlobalContext().getConfigDir(), KEY_BACKUP_DIR);
if (backupDir.isDirectory() || backupDir.mkdir()) {
String name = b32 + '-' + I2PAppContext.getGlobalContext().clock().now() + ".dat";
File backup = new File(backupDir, name);
if (FileUtil.copy(keyFile, backup, false, true))
log("Private key backup saved to " + backup.getAbsolutePath());
}
} catch (I2PException ie) {
if (_log.shouldLog(Log.ERROR))
_log.error("Error creating new destination", ie);
@@ -307,7 +320,9 @@ public class TunnelController implements Logging {
I2PSession session = sessions.get(i);
if (_log.shouldLog(Log.INFO))
_log.info("Acquiring session " + session);
TunnelControllerGroup.getInstance().acquire(this, session);
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
if (group != null)
group.acquire(this, session);
}
_sessions = sessions;
} else {
@@ -326,7 +341,9 @@ public class TunnelController implements Logging {
I2PSession s = _sessions.get(i);
if (_log.shouldLog(Log.INFO))
_log.info("Releasing session " + s);
TunnelControllerGroup.getInstance().release(this, s);
TunnelControllerGroup group = TunnelControllerGroup.getInstance();
if (group != null)
group.release(this, s);
}
// _sessions.clear() ????
} else {
@@ -536,8 +553,8 @@ public class TunnelController implements Logging {
/** default true */
public String getSharedClient() { return _config.getProperty("sharedClient", "true"); }
/** default true */
public boolean getStartOnLoad() { return Boolean.valueOf(_config.getProperty("startOnLoad", "true")).booleanValue(); }
public boolean getPersistentClientKey() { return Boolean.valueOf(_config.getProperty("option.persistentClientKey")).booleanValue(); }
public boolean getStartOnLoad() { return Boolean.parseBoolean(_config.getProperty("startOnLoad", "true")); }
public boolean getPersistentClientKey() { return Boolean.parseBoolean(_config.getProperty("option.persistentClientKey")); }
public String getMyDestination() {
if (_tunnel != null) {

View File

@@ -12,27 +12,35 @@ import java.util.Properties;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.app.*;
import static net.i2p.app.ClientAppState.*;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.data.DataHelper;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.OrderedProperties;
import net.i2p.util.SystemVersion;
/**
* Coordinate a set of tunnels within the JVM, loading and storing their config
* to disk, and building new ones as requested.
*
* Warning - this is a singleton. Todo: fix
* This is the entry point from clients.config.
*/
public class TunnelControllerGroup {
private Log _log;
private static TunnelControllerGroup _instance;
public class TunnelControllerGroup implements ClientApp {
private final Log _log;
private volatile ClientAppState _state;
private final I2PAppContext _context;
private final ClientAppManager _mgr;
private static volatile TunnelControllerGroup _instance;
static final String DEFAULT_CONFIG_FILE = "i2ptunnel.config";
private final List<TunnelController> _controllers;
private String _configFile = DEFAULT_CONFIG_FILE;
private final String _configFile;
private static final String REGISTERED_NAME = "i2ptunnel";
/**
* Map of I2PSession to a Set of TunnelController objects
* using the session (to prevent closing the session until
@@ -41,48 +49,145 @@ public class TunnelControllerGroup {
*/
private final Map<I2PSession, Set<TunnelController>> _sessions;
/**
* In I2PAppContext will instantiate if necessary and always return non-null.
* As of 0.9.4, when in RouterContext, will return null (except in Android)
* if the TCG has not yet been started by the router.
*
* @throws IllegalArgumentException if unable to load from i2ptunnel.config
*/
public static TunnelControllerGroup getInstance() {
synchronized (TunnelControllerGroup.class) {
if (_instance == null)
_instance = new TunnelControllerGroup(DEFAULT_CONFIG_FILE);
if (_instance == null) {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
if (SystemVersion.isAndroid() || !ctx.isRouterContext()) {
_instance = new TunnelControllerGroup(ctx, null, null);
_instance.startup();
} // else wait for the router to start it
}
return _instance;
}
}
private TunnelControllerGroup(String configFile) {
_log = I2PAppContext.getGlobalContext().logManager().getLog(TunnelControllerGroup.class);
_controllers = Collections.synchronizedList(new ArrayList());
_configFile = configFile;
/**
* Instantiation only. Caller must call startup().
* Config file problems will not throw exception until startup().
*
* @param mgr may be null
* @param args one arg, the config file, if not absolute will be relative to the context's config dir,
* if empty or null, the default is i2ptunnel.config
* @since 0.9.4
*/
public TunnelControllerGroup(I2PAppContext context, ClientAppManager mgr, String[] args) {
_state = UNINITIALIZED;
_context = context;
_mgr = mgr;
_log = _context.logManager().getLog(TunnelControllerGroup.class);
_controllers = new ArrayList();
if (args == null || args.length <= 0)
_configFile = DEFAULT_CONFIG_FILE;
else if (args.length == 1)
_configFile = args[0];
else
throw new IllegalArgumentException("Usage: TunnelControllerGroup [filename]");
_sessions = new HashMap(4);
loadControllers(_configFile);
I2PAppContext.getGlobalContext().addShutdownTask(new Shutdown());
synchronized (TunnelControllerGroup.class) {
if (_instance == null)
_instance = this;
}
if (_instance != this) {
_log.logAlways(Log.WARN, "New TunnelControllerGroup, now you have two");
if (_log.shouldLog(Log.WARN))
_log.warn("I did it", new Exception());
}
_state = INITIALIZED;
}
/**
* @param args one arg, the config file, if not absolute will be relative to the context's config dir,
* if no args, the default is i2ptunnel.config
* @throws IllegalArgumentException if unable to load from config from file
*/
public static void main(String args[]) {
synchronized (TunnelControllerGroup.class) {
if (_instance != null) return; // already loaded through the web
if ( (args == null) || (args.length <= 0) ) {
_instance = new TunnelControllerGroup(DEFAULT_CONFIG_FILE);
} else if (args.length == 1) {
_instance = new TunnelControllerGroup(args[0]);
} else {
System.err.println("Usage: TunnelControllerGroup [filename]");
return;
}
_instance = new TunnelControllerGroup(I2PAppContext.getGlobalContext(), null, args);
_instance.startup();
}
}
/**
* ClientApp interface
* @throws IllegalArgumentException if unable to load config from file
* @since 0.9.4
*/
public void startup() {
loadControllers(_configFile);
if (_mgr != null)
_mgr.register(this);
// RouterAppManager registers its own shutdown hook
else
_context.addShutdownTask(new Shutdown());
}
/**
* ClientApp interface
* @since 0.9.4
*/
public ClientAppState getState() {
return _state;
}
/**
* ClientApp interface
* @since 0.9.4
*/
public String getName() {
return REGISTERED_NAME;
}
/**
* ClientApp interface
* @since 0.9.4
*/
public String getDisplayName() {
return REGISTERED_NAME;
}
/**
* @since 0.9.4
*/
private void changeState(ClientAppState state) {
changeState(state, null);
}
/**
* @since 0.9.4
*/
private synchronized void changeState(ClientAppState state, Exception e) {
_state = state;
if (_mgr != null)
_mgr.notify(this, state, null, e);
}
/**
* Warning - destroys the singleton!
* @since 0.8.8
*/
private static class Shutdown implements Runnable {
private class Shutdown implements Runnable {
public void run() {
shutdown();
}
}
/**
* ClientApp interface
* @since 0.9.4
*/
public void shutdown(String[] args) {
shutdown();
}
/**
* Warning - destroys the singleton!
* Caller must root a new context before calling instance() or main() again.
@@ -91,28 +196,33 @@ public class TunnelControllerGroup {
*
* @since 0.8.8
*/
public static void shutdown() {
public synchronized void shutdown() {
if (_state != STARTING && _state != RUNNING)
return;
changeState(STOPPING);
if (_mgr != null)
_mgr.unregister(this);
unloadControllers();
synchronized (TunnelControllerGroup.class) {
if (_instance == null) return;
_instance.unloadControllers();
_instance._log = null;
_instance = null;
if (_instance == this)
_instance = null;
}
/// fixme static
I2PTunnelClientBase.killClientExecutor();
changeState(STOPPED);
}
/**
* Load up all of the tunnels configured in the given file (but do not start
* them)
*
* DEPRECATED for use outside this class. Use startup() or getInstance().
*
* @throws IllegalArgumentException if unable to load from file
*/
public void loadControllers(String configFile) {
public synchronized void loadControllers(String configFile) {
changeState(STARTING);
Properties cfg = loadConfig(configFile);
if (cfg == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Unable to load the config from " + configFile);
return;
}
int i = 0;
while (true) {
String type = cfg.getProperty("tunnel." + i + ".type");
@@ -127,20 +237,28 @@ public class TunnelControllerGroup {
if (_log.shouldLog(Log.INFO))
_log.info(i + " controllers loaded from " + configFile);
changeState(RUNNING);
}
private class StartControllers implements Runnable {
public void run() {
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
if (controller.getStartOnLoad())
controller.startTunnel();
synchronized(TunnelControllerGroup.this) {
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
if (controller.getStartOnLoad())
controller.startTunnel();
}
}
}
}
public void reloadControllers() {
/**
* Stop all tunnels, reload config, and restart those configured to do so.
* WARNING - Does NOT simply reload the configuration!!! This is probably not what you want.
*
* @throws IllegalArgumentException if unable to reload config file
*/
public synchronized void reloadControllers() {
unloadControllers();
loadControllers(_configFile);
}
@@ -150,7 +268,7 @@ public class TunnelControllerGroup {
* file or do other silly things)
*
*/
public void unloadControllers() {
public synchronized void unloadControllers() {
stopAllControllers();
_controllers.clear();
if (_log.shouldLog(Log.INFO))
@@ -162,14 +280,14 @@ public class TunnelControllerGroup {
* a config file or start it or anything)
*
*/
public void addController(TunnelController controller) { _controllers.add(controller); }
public synchronized void addController(TunnelController controller) { _controllers.add(controller); }
/**
* Stop and remove the given tunnel
*
* @return list of messages from the controller as it is stopped
*/
public List<String> removeController(TunnelController controller) {
public synchronized List<String> removeController(TunnelController controller) {
if (controller == null) return new ArrayList();
controller.stopTunnel();
List<String> msgs = controller.clearMessages();
@@ -183,7 +301,7 @@ public class TunnelControllerGroup {
*
* @return list of messages the tunnels generate when stopped
*/
public List<String> stopAllControllers() {
public synchronized List<String> stopAllControllers() {
List<String> msgs = new ArrayList();
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
@@ -200,7 +318,7 @@ public class TunnelControllerGroup {
*
* @return list of messages the tunnels generate when started
*/
public List<String> startAllControllers() {
public synchronized List<String> startAllControllers() {
List<String> msgs = new ArrayList();
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
@@ -218,7 +336,7 @@ public class TunnelControllerGroup {
*
* @return list of messages the tunnels generate when restarted
*/
public List<String> restartAllControllers() {
public synchronized List<String> restartAllControllers() {
List<String> msgs = new ArrayList();
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
@@ -235,7 +353,7 @@ public class TunnelControllerGroup {
*
* @return list of messages the tunnels have generated
*/
public List<String> clearAllMessages() {
public synchronized List<String> clearAllMessages() {
List<String> msgs = new ArrayList();
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
@@ -257,8 +375,7 @@ public class TunnelControllerGroup {
* Save the configuration of all known tunnels to the given file
*
*/
public void saveConfig(String configFile) throws IOException {
_configFile = configFile;
public synchronized void saveConfig(String configFile) throws IOException {
File cfgFile = new File(configFile);
if (!cfgFile.isAbsolute())
cfgFile = new File(I2PAppContext.getGlobalContext().getConfigDir(), configFile);
@@ -279,16 +396,17 @@ public class TunnelControllerGroup {
/**
* Load up the config data from the file
*
* @return properties loaded or null if there was an error
* @return properties loaded
* @throws IllegalArgumentException if unable to load from file
*/
private Properties loadConfig(String configFile) {
private synchronized Properties loadConfig(String configFile) {
File cfgFile = new File(configFile);
if (!cfgFile.isAbsolute())
cfgFile = new File(I2PAppContext.getGlobalContext().getConfigDir(), configFile);
if (!cfgFile.exists()) {
if (_log.shouldLog(Log.ERROR))
_log.error("Unable to load the controllers from " + cfgFile.getAbsolutePath());
return null;
throw new IllegalArgumentException("Unable to load the controllers from " + cfgFile.getAbsolutePath());
}
Properties props = new Properties();
@@ -298,7 +416,7 @@ public class TunnelControllerGroup {
} catch (IOException ioe) {
if (_log.shouldLog(Log.ERROR))
_log.error("Error reading the controllers from " + cfgFile.getAbsolutePath(), ioe);
return null;
throw new IllegalArgumentException("Error reading the controllers from " + cfgFile.getAbsolutePath(), ioe);
}
}
@@ -307,7 +425,9 @@ public class TunnelControllerGroup {
*
* @return list of TunnelController objects
*/
public List<TunnelController> getControllers() { return _controllers; }
public synchronized List<TunnelController> getControllers() {
return new ArrayList(_controllers);
}
/**

Some files were not shown because too many files have changed in this diff Show More