Compare commits

...

1228 Commits

Author SHA1 Message Date
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
zab
1fa00a5738 Restore javadocs 2012-12-10 18:05:52 +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
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
zab
1e83028702 An ArrayList that reuses a single iterator 2012-11-22 21:50:48 +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
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
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
f16e83f21b 0.9.2 2012-09-21 14:24:53 +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
meeh
ee66747def Fix after review and install on fresh osx (lession learned: test clean installs) 2012-09-17 20:33:03 +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
ccb8483766 * Build: Fix unpack problem on Java 5: http://forum.i2p/viewtopic.php?t=7334 2012-09-15 13:12:00 +00:00
zzz
68ccb3a944 cleanup 2012-09-14 13:53:36 +00:00
zzz
b317eca5e3 * SSU: Fix shutdown NPE (ticket #709) 2012-09-14 13:50:06 +00:00
zzz
5ffacccdd7 update geoip license 2012-09-14 13:49:32 +00:00
zzz
a41936af94 typo 2012-09-14 13:49:09 +00:00
kytv
0991adc291 GeoIPdb update based on Maxmind GeoLite Country database from 2012-09-05 2012-09-13 16:15:09 +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
kytv
7820cef60a Czech language translation updates from transifex
(and updated en po files)
2012-09-12 12:04:43 +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
kytv
cb39006f6c minor corrections after review
The newly added OSX bits by meeh (thanks!) do not require Izpack to perform
substitutions, so I'm removing those files from the <parseable> tags.
2012-09-10 10:51:17 +00:00
meeh
52447096f2 Added a fix for a startup issue in newer versions of launchd. Setting Disabled
in configfile will only work on older launchd version. Ref manpage:
  (-w Overrides the Disabled key and sets it to false. In previous ver-
      sions, this option would modify the configuration file. Now the
      state of the Disabled key is stored elsewhere on-disk.)
2012-09-10 03:14:09 +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
meeh
5056706742 Added command scripts for osx to install i2p as a daemon in launchd.
.command extension make it possible to double click on it like bat files
in windows. Daemon is runned as the user who executes the command file.
2012-09-05 21:36:24 +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
9fd2f1e6a7 SSU: Fix some issues with queueing outbound establishments 2012-09-04 13:51:55 +00:00
zzz
b98474880d OutNetMessage: Speedup after profiling (ticket #707 - thx dg, kytv, zab) 2012-09-04 13:50:24 +00:00
zzz
5347d296dc log tweak 2012-09-04 13:46:52 +00:00
zzz
666a387d1b log fix 2012-09-04 13:46:31 +00:00
zzz
bb66e16b69 I2PTunnelServer: Clean shutdown after session exception 2012-09-04 13:46:10 +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
kytv
0ba3aad666 Disable i2jump.i2p from the tunnel wizard since it's been disabled elsewhere 2012-09-01 15:02:38 +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
a5e4b15349 add irc.killyourtv.i2p 2012-08-31 14:47:14 +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
7cc353ab04 javadoc 2012-08-31 14:36:53 +00:00
zzz
506626d6b1 i2psnark: Remove * from magnet and download names 2012-08-31 13:58:37 +00:00
zzz
26898f38ad Startup: Don't complain about clients.config missing on Android 2012-08-31 13:57:24 +00:00
zzz
4fdff1bf13 Router: Lengthen shutdown spinner life 2012-08-31 13:56:24 +00:00
sponge
7d4a6e74d2 Report no bugs in Android BitSet 2012-08-31 03:53:19 +00:00
sponge
b33a01cf26 use index instead of upper and lower, it's the same thing, but makes more sense. 2012-08-31 02:37:15 +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
kytv
a4511ca2ab typo fix 2012-08-29 19:17:40 +00:00
zzz
17b4ab6151 message cleanup 2012-08-29 14:16:19 +00:00
zzz
d2a7af2884 refactor trimmers to their own files 2012-08-29 14:05:02 +00:00
zzz
d05f1ca2c8 RandomIterator: Workaround for Android bug (ticket #703)
Include test case
2012-08-29 13:59:44 +00:00
zzz
832d66bfb9 NTCP: Reduce lock contention (ticket #697) 2012-08-29 13:47:05 +00:00
zzz
c8a46dac5d i2psnark:
- Add new flood-resistant KBucket trim policy
   - Limit received MsgID size
2012-08-29 13:45:29 +00:00
zzz
7005376061 - Fix NPE on destroy() if init() failed 2012-08-29 13:29:13 +00:00
zzz
ab213f45e2 cleanups 2012-08-29 13:28:03 +00:00
zzz
fa504ae8a3 - Fix cases where we weren't using the session for b32 lookup 2012-08-27 21:36:39 +00:00
zzz
d305eb6a9c * SSU:
- Limit UDPSender queue size
   - Increase UDPSender max packet lifetime
   - Clear UDPSender queue before sending destroys to all
   - Increase PeerState queue size so large streaming windows
     don't get dropped right away, especially at slow start
   - Various improvements on iterating over pending outbound
     messages in PeerState
2012-08-27 20:39:00 +00:00
zzz
f8bc6f8612 * Streaming: Limit amount of slow-start exponential growth 2012-08-27 20:36:24 +00:00
zzz
9099937119 * Reseed: Remove forum.i2p2.de 2012-08-27 20:35:02 +00:00
zzz
b827468e2f * i2psnark: Notify threads awaiting DHT replies at shutdown 2012-08-27 20:34:19 +00:00
zzz
587795552e Wrapper files for armv7.
Compiled on trimslice:
    gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) 
    java version "1.6.0_18"
    OpenJDK Runtime Environment (IcedTea6 1.8.13) (6b18-1.8.13-0ubuntu1~11.04.1)
    OpenJDK Zero VM (build 14.0-b16, mixed mode)
    Wrapper 3.5.15 GPLv2
    All binaries stripped.
2012-08-27 17:43:04 +00:00
kytv
0a1ff9b6bd Update Java Service Wrapper to v3.5.15.
- 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.
 - Linux ARMv5 & PPC32: Self-compiled in Debian Squeeze
 - Linux x86, Linux x64, MacOSX & Solaris: Binares are from the "community
   edition" deltapack offered by Tanuki. The x86 and x64 binaries for Linux
   have been stripped.
2012-08-27 13:49:18 +00:00
zzz
b01cf32321 * SendMessageOptions: Increase tag fields to 4 bits and use
table lookup for more flexibility
 * Streaming: Use packet type and current window size to adjust
              number of tags sent and tag threshold, to improve
              efficiency and reliability
2012-08-26 13:02:11 +00:00
zzz
9ba6c293ed * DataHelper: Trim trailing whitespace when loading properties 2012-08-26 12:54:49 +00:00
zzz
99681e1d1e * NetDB: Increase floodfills, decrease flood redundancy 2012-08-26 12:47:31 +00:00
kytv
96775acf5a Dutch and German translation updates from TX 2012-08-25 19:43:25 +00:00
kytv
ba992067ad typo fixes (ticket #701), thanks vz 2012-08-25 19:05:45 +00:00
zzz
2552d99308 * Other object churn cleanups (ticket #699) 2012-08-25 14:48:39 +00:00
zzz
e99e25b3b9 minor cleanup 2012-08-25 14:45:31 +00:00
zzz
70820d7be6 * SDSCache: Reduce min and increase max size
* SimpleByteCache: Change from LBQ to ABQ to reduce object churn
2012-08-25 14:44:52 +00:00
zzz
38fda46d44 javadoc 2012-08-25 14:42:04 +00:00
zzz
9d383d6aef * i2psnark:
- Use extended I2CP options for datagrams
   - Fix timeout for sent datagrams
   - Reduce token timeout
   - Check token age before use
   - Limit incoming token size
2012-08-24 22:13:08 +00:00
zzz
ba0408a741 * I2CP:
- Add methods for sending a message with extended options
   - Fix cases where the efficient sendNoEffort() wasn't being used
 * OCMOSJ:
   - Implement per-message overrides for tag threshold,
     tags to send, and bundle leaseset
   - Fix bug adjusting timeouts
   - Warn on client expiration time bugs
2012-08-24 22:11:02 +00:00
zzz
07c21c3bfd - Add link for local torrent file on details page
- Show totals line even if only one torrent
2012-08-24 22:07:00 +00:00
zzz
5ffefd2a19 * Crypto: Rename bouncycastle HMAC libs so they don't conflict
with older Android versions which bundle them
2012-08-23 19:11:55 +00:00
zzz
e3e15850bb * SSU:
- Don't relay or introduce to/from privileged ports
   - Various spoof detections
2012-08-23 19:10:36 +00:00
zzz
54b367b153 * NTCP: Reduce lock contention 2012-08-23 19:08:45 +00:00
zzz
b61127270e * SSU:
- Fail establishment immediately on SessionCreated
     validation fail
   - Defer outbound DH generation until required
   - Validate address/port in RelayIntro messages
   - Throttle hole punches
   - More cleanups
2012-08-22 17:43:09 +00:00
zzz
1d41c2fd19 SSU: Workaround for Android ICS bug 2012-08-22 17:41:43 +00:00
zzz
7c7e131dc0 * SimpleTimer2: Synchronization improvements (ticket #653) 2012-08-22 17:40:47 +00:00
zzz
85fbbf8980 * NetDB: Add hash collision detection 2012-08-22 17:40:25 +00:00
zzz
612fab1b2a * SSU:
- Use external, not internal port to sign SessionCreated message.
     Together with previous fix to allow external port change, this
     should fix session establish fails when NAT changes our port
   - Track outbound establishments by both Hash and IP/port,
     to improve lookups of establishments in progress
   - Fix expiration of outbound establishments
   - Validate address/port in RelayResponse messages
   - Change RemoteHostID to store Hash instead of byte[] for the peer hash
   - Log tweaks
2012-08-21 19:53:08 +00:00
zzz
fbd8c69eea * NetDB: Decrease stat publish probability 2012-08-21 19:49:43 +00:00
zzz
8fcac04aad javadoc 2012-08-21 19:48:18 +00:00
zzz
7d902cca1e log tweak 2012-08-21 19:48:04 +00:00
meeh
ddc1d7c6bc disapproval of revision 'acc7942148f44d32fc600d2f5784d1a43496eada' 2012-08-20 21:26:12 +00:00
meeh
5bb90c6185 * Fixed the FIXME in createInstance where the method failed to ensures that there will be only one naming service instance. 2012-08-20 18:28:20 +00:00
zzz
9452547204 * SSU: Allow port change if firewalled
* UPnP:
   - Prep for UPnP returning different external port
   - Better logging of errors
2012-08-20 12:22:00 +00:00
zzz
34c09583b4 do not use 8887 default in UI 2012-08-20 12:14:43 +00:00
zzz
38b0927d01 * I2CP: MessageStatus cleanup 2012-08-20 12:13:26 +00:00
zzz
715bde5ecf * Streaming: Increase max connection timeout 2012-08-20 12:12:48 +00:00
zzz
6c2eb317fe * I2PTunnelRunner: Remove unnecessary lock (ticket #690) 2012-08-20 12:10:10 +00:00
zzz
05516f3260 * i2psnark: Add minimum tracker and DHT announce intervals 2012-08-20 12:09:20 +00:00
kytv
264df83943 fix hang during uninstallation (#656) 2012-08-18 13:06:07 +00:00
zzz
3a546612d9 * SSU:
- Use remote MTU when published (ticket #687)
   - Queue outbound msgs during inbound establish
   - IntroManager cleanups
   - More synchronization
   - More log tweaks
2012-08-17 14:15:01 +00:00
zzz
3cac01ff27 * i2psnark:
- Adjust DHT timeouts
   - Add max peers per-torrent in tracker
   - Remove duplicate clean task for nodes
   - Fix another DHT warning message
2012-08-17 14:09:49 +00:00
sponge
e01521618f BOB: just some cleanup 2012-08-17 05:39:02 +00:00
zzz
ee63f3b86d minor NTCP cleanup 2012-08-16 19:02:38 +00:00
zzz
a900511d5e * Utils: Drop unused BufferedRandomSource, PooledRandomSource,
EepGetScheduler, EepPost and HTTPSendData, moved to i2p.scripts
2012-08-16 18:25:49 +00:00
zzz
3fe092d788 tab cleanup 2012-08-16 18:24:59 +00:00
zzz
e2fe5004e7 javadoc fixes 2012-08-15 14:39:52 +00:00
zzz
442af031eb propagate from branch 'i2p.i2p.zzz.upnp' (head fbd68f812db1e891f96e212b3a5938beec0233b5)
to branch 'i2p.i2p' (head a8d4956565f7c58736c2a3001f2b08ecff59ab57)
2012-08-15 14:29:30 +00:00
zzz
e22882bd02 - More fixups from merge
- Remove local address from thread names for thread dump anonymity
2012-08-15 14:24:40 +00:00
zzz
523d39b3bb * i2psnark:
- Fix bug preventing completion announcement, broken in 0.9.1
   - Fix setting short retry time after initial announce failure
   - Fix DHT announce and getPeers
   - Fix DHT warning message
   - log tweaks
2012-08-15 12:44:46 +00:00
zzz
65efefb094 propagate from branch 'i2p.i2p' (head 51b3351f42e7ff6e2f2bd8512e4b4402e08631f4)
to branch 'i2p.i2p.zzz.upnp' (head d28cfe73c2741ea264f73a7317f8a9919e108170)
2012-08-14 13:50:15 +00:00
zzz
44edf70842 * SSU EstablishmentManager: Fix bug with OB establishment via introducers
- log tweaks
2012-08-13 23:06:07 +00:00
zzz
16a46b3211 * SSU EstablishmentManager:
- Remove use of outbound timers in EstablishmentManager; drive all events in Establisher thread
   - Don't change nonces when retransmitting intro packets
   - More synchronization in EstablishmentManager
   - Increase establishment timeouts and implement timeouts for individual phases (ticket #669)
   - Fix bug where InboundEstablishState.createdPacketSent() wasn't being called,
     so SessionCreated packets weren't retransmitted
   - Increase retransmission timeout for SessionCreated and implement backoff
   - Send destroy if establishment times out in the middle
   - Fix code that pulls outbound states off a deferred queue
   - Improve UDPPacket.toString() for debugging
   - More logging of packets dropped in EstablishmentManager
   - Change establish states to enums
2012-08-13 15:12:33 +00:00
zzz
e9cc85141c comparator cleanups 2012-08-13 15:08:06 +00:00
zzz
cfcafd2ba3 * SSU:
- Reject some packet types if they came in via fallback introKey
   - Increase retransmission timeout for SessionRequest, SessionConfirm,
     and RelayRequest; implement backoff
   - Move UDPFlooder to test
   - More volatiles, finals, cleanups, stat removals, log tweaks
2012-08-12 11:24:15 +00:00
zzz
e67dd15308 * PeerManager: Fix NPE on Android (ticket #687) 2012-08-12 11:19:49 +00:00
zzz
a76f840ff8 remove finalize 2012-08-12 11:18:24 +00:00
zzz
269a36c549 * Jetty: Don't use direct byte buffers that may be leaking (ticket #679) 2012-08-12 11:11:45 +00:00
str4d
36bf248385 Removed unnecessary <p></p> around <img> on /graph 2012-08-12 00:35:09 +00:00
kytv
046135f8e3 merge of '8027b8544962ebd34af3edfe73bbc8195f8c1e90'
and '871249c3be5c8d8ce83a539ba8c5409876ef3a44'
2012-08-11 14:47:43 +00:00
meeh
97e469da7b command safari does not exist. using command "open" instead. 2012-08-11 14:34:20 +00:00
zzz
01beb015dc merge of '52c0538bb3404f46ac4fde538794a547852d5d44'
and 'e40ee84836983c85a8985c0a76e9e5a7635002cd'
2012-08-11 13:55:55 +00:00
zzz
50d5692884 snark build fix sorry 2012-08-11 13:51:52 +00:00
meeh
0ea6513e9c Changed my reseed url to contain a subpath, /netDb/. also updated the certificate (forgot to copy out of conf folder when i changed webserver and deleted config). 2012-08-11 13:43:48 +00:00
zzz
e2b683556b merge of '15095538e7b5c72468863e969541571ade1796f9'
and '39af5d31a13c5d5b71107e2caa0c234b84827c03'
2012-08-11 12:26:32 +00:00
zzz
14587ebb59 dash six 2012-08-11 12:16:43 +00:00
zzz
be3cf44608 get rid of one more UnsupportedOperationException 2012-08-11 11:41:29 +00:00
zzz
1538cd84a9 * DataHelper: toString(byte[]) cleanup and javadoc 2012-08-11 11:40:41 +00:00
meeh
f5b808b997 OSX: Fixed a bug in OS_VER variable.
the old version (grep -o '[0-9]*\.[0-9]*\.[0-9]*') won't detect versions as 10.8, or 10.7
added cut -d: -f2 | sed -e 's/[^0-9]*//' , matching both 10.8, 10.7.4, etc.
2012-08-11 11:40:05 +00:00
zzz
f92d8aed3d make context list concurrent 2012-08-11 11:34:32 +00:00
zzz
f6c769187e fix 2012-08-11 11:33:43 +00:00
zzz
c70e3727be * SSU MTU (ticket #682):
- Use local MTU detection
   - i2np.udp.mtu now sets max MTU, not initial MTU
   - Put local MTU in netDb 
   - Fix receive MTU calculations
   - Track remote MTU based on actual received packet size
   - Display local MTU on peers page
2012-08-11 11:27:28 +00:00
zzz
a6a0228ef8 * i2psnark: Fix DHT nodes not being saved at shutdown
Log infohashes in hex
             Don't write out nodes if we don't have any
2012-08-11 11:23:27 +00:00
meeh
d2a5595df2 Added new reseed host, and a self signed certificate for that host. 2012-08-11 01:14:58 +00:00
kytv
e9c07a123a German and Greek translation updates from Transifex 2012-08-11 00:25:43 +00:00
meeh
1e8e2a197b A fix for ticket #684 2012-08-10 23:55:14 +00:00
zzz
39d9d3f5b6 * SAM: Don't use direct byte buffers for streams (ticket #679)
DatagramServer one stays as it is a singleton.
2012-08-09 15:12:17 +00:00
zzz
8bada7f882 merge of '01c1a5c0e70a460534e66dd487aa8676d666168d'
and '441b352d1cef1c64ee96f55692be67cfc4b4abf1'
2012-08-09 15:03:01 +00:00
kytv
a940062255 add ')' missing from str4d's checkins 2012-08-09 11:35:41 +00:00
str4d
93efd31a5b merge of '62c3f266fd9443e9d7b3f71be8f4b36b4952f96b'
and 'd71795fa9a3d5fa0349f46eef4062670755b2cff'
2012-08-09 02:37:19 +00:00
str4d
2e9fdc6d9f Updated history.txt 2012-08-09 02:36:39 +00:00
zzz
b9f5f230a2 stub out local MTU detection (ticket 682) 2012-08-08 23:36:11 +00:00
zzz
0a751a303f post-0.9 cleanup 2012-08-08 17:09:28 +00:00
zzz
b2da629034 * Datagrams: Remove static logs 2012-08-08 17:07:28 +00:00
zzz
37a542c009 NTCP stat cleanup 2012-08-08 17:06:33 +00:00
zzz
0451ee7f08 * SSU: More cleanups; don't send a packet that exceeds the MTU 2012-08-08 17:05:42 +00:00
zzz
d8dd76c6e0 * SAM: Volatiles and finals 2012-08-08 17:01:59 +00:00
zzz
9cee0ee504 * i2psnark:
- Remove static SnarkManager instance
   - Allow DHT-only torrents
   - DHT debugging
2012-08-08 17:00:33 +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
58a545d30c Snark: explicitly check if universal theme is "classic", and use "light" if so 2012-08-07 23:08:37 +00:00
str4d
dfb0b7801d Updates to classic console theme from dr|z3d 2012-08-07 23:03:34 +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
a21175d903 propagate from branch 'i2p.i2p' (head b1fe8f8037e6dd8a1f6be6e30151ad0ca92e6689)
to branch 'i2p.i2p.str4d.fux' (head 723929af49930ca764fe4befb3621a036a3f99b8)
2012-08-07 12:28:30 +00:00
str4d
9c7f4cc604 merge of '6014a9321bb2362ffc628a351c1db19922384f76'
and 'd68b6ad6b4308d8dbe27d1faac089cb15358bfa2'
2012-08-07 12:24:33 +00:00
str4d
3017e4f51a Fixed .mtn-ignore to ignore build dirs properly 2012-08-07 12:18:16 +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
5ed1ec681f Updates to classic console theme from dr|z3d 2012-08-07 11:42:22 +00:00
str4d
0a4031cd7b Updates to midnight console theme from dr|z3d 2012-08-07 06:03:35 +00:00
str4d
31ea4a7093 Changed universal theming prop key (so not mistaken as a theme name by routerconsole) 2012-08-07 04:29:50 +00:00
str4d
0ca2d33ee1 New midnight theme for susidns from dr|z3d 2012-08-07 04:24:41 +00:00
str4d
48bcd3a8c2 Updates to console and snark themes from dr|z3d 2012-08-07 04:22:40 +00:00
zzz
1ab8200c7f * Clone System properties before iterating to avoid
ConcurrentModificationException (ticket #680)
2012-08-06 14:45:37 +00:00
zzz
91e61dbd5c fix flag links so language selection returns to the same page 2012-08-06 14:13:15 +00:00
zzz
fb4ef57148 propagate from branch 'i2p.i2p.zzz.dhtsnark' (head d4f16babae7cb0156609b211f5bb0310b03aaf57)
to branch 'i2p.i2p' (head 7bcd2f192b0f571374cc9882eca407095eb97c17)
2012-08-06 14:05:09 +00:00
zzz
ced0129e03 * libjbigi.so for ARMv6
GMP 4.3.2
    Compiled on Raspberry Pi with gcc version: gcc (Debian 4.6.3-8+rpi1) 4.6.3
    java version "1.6.0_24"
    OpenJDK Runtime Environment (IcedTea6 1.11.3) (6b24-1.11.3-2+rpi1)
    OpenJDK Zero VM (build 20.0-b12, mixed mode)
    Stripped.
    Had a report that the ARMv5 jbigi worked on the RPi but it didn't for me.
    See NativeBigInteger for more info.
    /proc/cpuinfo:

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-08-06 14:04:32 +00:00
str4d
740b6501cd Updated history.txt 2012-08-06 12:38:00 +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
67f16b0de4 javadocs 2012-08-05 16:55:39 +00:00
zzz
fd3d92d3b2 merge of '1045fe48c576267959eae499a22776d9f9acafc3'
and 'bed1572eff55282ffcb5a2b92d02813eb04c0548'
2012-08-05 15:16:45 +00:00
zzz
5ba5d537b5 * UDP:
- Limit PacketHandler threads to 1 (ticket #660)
   - Limit queue sizes between UDPReceiver and PacketHandler,
     and between PacketHandler and MessageReceiver, to prevent OOMs
     and/or excessive queue delays
   - Increase UDPPacket cache size based on max mem
   - Remove more stats
2012-08-05 14:24:14 +00:00
zzz
4efa87d6bf * i2ptunnel, I2CP, EepGet: Buffer socket input streams (ticket #666)
* I2PSessionImpl: One more volatile (ticket #659)
2012-08-05 13:33:28 +00:00
str4d
442897ba5b merge of '48ea7675889a36bfb253833a66c22275abcee355'
and '925b1411e60b0e76e2421becd84d6c63832b69bb'
2012-08-05 07:40:05 +00:00
kytv
2b79da5c35 Debian: update patch to compensate for last commit
At the same time I'm making more Debian-specific changes, such as
 - not checking for Gentoo (this is obviously never going to be true :P)
 - not mentioning IzPack replacing variables (also not applicable)
 - inform about dpkg-reconfigure i2p in the event someone tries to remove or
   install an initscript with "i2prouter install|remove|uninstall"
 - remove the manual wrapper instructions
2012-08-04 17:44:09 +00:00
kytv
cc3a8e5d62 have izpack expand %USER_HOME in i2prouter
This will solve the issue of I2P_CONFIG_DIR being set incorrectly if another
user runs i2prouter once, such as when installing the initscript.
2012-08-04 17:32:11 +00:00
zzz
280a708afe - Change secure Node ID requirements again
- Protect against null DHT races
- Add message about restarting tunnel when DHT config changes
- Add DHT size to table totals
2012-08-04 17:11:11 +00:00
str4d
f5a348a863 propagate from branch 'i2p.i2p.str4d.test' (head 190d9be59620f8c6f80e0cb2fc4d9fa839edbb4f)
to branch 'i2p.i2p' (head c884db74f90a9d1c33deca6e2fd2e29f6c1ac8fa)
2012-08-03 21:30:29 +00:00
str4d
85a4e9cb5c Clarified purpose of the default IRC tunnel (it's not a "proxy") 2012-08-03 21:26:09 +00:00
zzz
4715dbdbd0 fixup after prop 2012-08-03 20:40:31 +00:00
zzz
afad77af19 propagate from branch 'i2p.i2p' (head d2198c4bc21a9d06194cdb2dce24945ebc9d1542)
to branch 'i2p.i2p.zzz.dhtsnark' (head 59fc0206608a5d1323a0acfbcb151d862fe95f95)
2012-08-03 20:29:31 +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
b4a50ed03a replace SimpleScheduler.getInstance() calls 2012-08-03 17:13:17 +00:00
zzz
00f9fea98c replace SimpleTimer2.getInstance() calls 2012-08-03 16:23:31 +00:00
zzz
501651125f * UDP:
- Catch some cases where UDPPackets were not returned to the cache (ticket #675)
   - Fix inverted logging logic (ticket #663)
   - Remove check in UDPPacket.getLifetime() (ticket #664)
   - RemoteHostID cleanup, cache hashcode
   - Remove udp.fetchRemoteSlow stat
   - Remove some time stamping in UDPPacket
   - Other cleanups - see http://zzz.i2p/topics/1198
2012-08-03 14:25:32 +00:00
zzz
18e8d35910 * LogManager: Add logger.logBufferSize and logger.dropOnOverflow options (ticket #662) 2012-08-03 13:42:40 +00:00
zzz
9e4d231285 final 2012-08-03 11:23:09 +00:00
zzz
2972e79f9e * OutNetMessage: Fix NPE when log level = INFO (ticket #676) 2012-08-03 11:22:48 +00:00
zzz
4d32eaa036 * JobQueue: Synch fix (ticket #670) 2012-08-03 11:21:28 +00:00
zzz
e4f141b94c * build.xml: Add buildI2PTunnelJar target for Android 2012-08-03 11:20:28 +00:00
zzz
ccf36abd30 * i2psnark: Finish migration to I2P logging to reduce object churn (ticket #673) 2012-08-03 11:19:52 +00:00
str4d
d147db3382 Only call SaveConfig once in ConfigUIHandler 2012-08-03 03:49:46 +00:00
str4d
9d29dc6b68 Fixed bugs introduced while reverting 2012-08-01 05:54:07 +00:00
str4d
6562b33bbc Removed readConfigFile and writeConfigFile from I2PAppContext (unnecessary now) 2012-08-01 03:05:18 +00:00
str4d
f58f297cdb Reverted susimail to storing theme itself, but checking routerconsole for universal theming 2012-08-01 03:00:23 +00:00
str4d
376b991b63 Reverted i2psnark to storing theme itself, but checking routerconsole for universal theming 2012-08-01 02:44:18 +00:00
str4d
120d31244e Reverted i2ptunnel to reading theme from routerconsole 2012-08-01 02:26:26 +00:00
str4d
679549cbf2 Reverted susidns to storing theme itself, but checking routerconsole for universal theming 2012-08-01 02:04:00 +00:00
str4d
a623d924fa Reverted routerconsole to storing theme itself, also store universal theming boolean 2012-08-01 01:50:59 +00:00
kytv
95fb141ad9 0.9.1 debian changelog 2012-08-01 00:34:17 +00:00
str4d
fad6f54794 propagate from branch 'i2p.i2p.unittests' (head 0c5ea65761d9127f160bccb3d1d157f8947ca050)
to branch 'i2p.i2p' (head e36d5669f32ad1a0f66ab84f7f9ff8fa2937680b)
2012-07-31 21:49:31 +00:00
str4d
e1525d98cd Fixed paths to JUnit tests in javadoc targets 2012-07-31 21:26:46 +00:00
str4d
3d69d2bf63 If the theme set for susidns doesn't exist, use the default instead 2012-07-31 12:56:23 +00:00
str4d
cb2dd03e77 Refactored writeConfigFile to use DataHelper.storeProps, tidied up logging 2012-07-31 12:52:31 +00:00
str4d
3253f82900 Added ScalaTest support to router build.xml 2012-07-31 00:06:28 +00:00
zzz
33a00efd82 * RoutingKeyGenerator: Cleanups (ticket #672) 2012-07-30 22:39:47 +00:00
zzz
8bcbf24713 propagate from branch 'i2p.i2p.zzz.test' (head 5474e1a513fc8144a3d855e9c85d8b235f7f9816)
to branch 'i2p.i2p' (head 5932d3923108572b22a8a7a600f0f9e62ecac347)
2012-07-30 22:29:02 +00:00
kytv
52ba727664 line ending fixes
These CSS files improperly contain a mixture of Windows *and* UNIX line
endings. Some lines had ^M after them but most didn't.
2012-07-30 17:01:12 +00:00
kytv
a1cfacd8da merge of '3347c631d86a2ccf634321b74e24b9a58e490a15'
and '95d885a94cdde7ad40bbef11ec76f86d1ea7b798'
2012-07-30 16:51:05 +00:00
str4d
5b6e7ba91d Added some skeleton Spec tests for various I2P data types in net.i2p.data 2012-07-30 14:50:51 +00:00
zzz
77a19a0b17 0.9.1 2012-07-30 13:28:56 +00:00
zzz
7ecb90640c fixes after review 2012-07-30 13:15:58 +00:00
str4d
691ce6fec7 The first ScalaTest specification: a Hash must be 32 bytes long 2012-07-30 12:36:00 +00:00
str4d
618f214a4f Added ScalaTest support to core build.xml
The old JUnit tests are still present, but "ant test" and "ant fulltest" default
to the (pending) ScalaTest ones. To run the ScalaTest tests with Cobertura, execute
the following:

ant -Dscalatest.libs=./lib -Dwith.cobertura=/usr/share/java/cobertura.jar fulltest

The scalatest.libs property must point to a directory containing scala-compiler.jar,
scala-library.jar and scalatest.jar.
2012-07-30 12:26:35 +00:00
str4d
48df91f796 Moved existing JUnit tests to junittest/ in preparation for ScalaTest 2012-07-30 04:04:07 +00:00
str4d
d27d0bd2e4 A couple more specific excludes for JUnit tests 2012-07-30 04:03:02 +00:00
str4d
39d954d56a merge of '00209f1054786667de66adbd6038fccf8825260f'
and '180794b6e2aad94450e102b4ac346f8172811ba1'
2012-07-28 22:22:07 +00:00
kytv
78b1922dd7 "11th hour" de & es translation updates from TX 2012-07-28 21:18:56 +00:00
str4d
639253e9bb Fixed a bug in a console_big.css override in light and dark themes 2012-07-28 13:45:12 +00:00
str4d
f8fe2a295f Fixed icon column width being too large in snark filemanager 2012-07-28 13:38:40 +00:00
str4d
9d2831f520 Updated history and bumped build number 2012-07-28 12:47:42 +00:00
str4d
c2438a7508 Fixed an i2ptunnel button regression in the dark console theme 2012-07-28 12:33:36 +00:00
zzz
4298958952 comment out tests 2012-07-27 15:49:46 +00:00
zzz
54a80d6bdc javadoc 2012-07-27 15:31:20 +00:00
zzz
aba655a9c7 move default properties from build.xml to build.properties 2012-07-27 15:30:11 +00:00
str4d
b6eef94383 Tweaked console themes so console error pages look alright in iframe
This fixes the issue where, when an iframed app was not running, the summary
bar would be displayed inside the iframe as well as outside it.
2012-07-27 12:41:45 +00:00
kytv
7526db9e6c minor update to reflect the other systems that we support 2012-07-26 21:11:42 +00:00
kytv
c853337d41 merge of '3b6726af78088f84c156c7d5cb40aa0b73946465'
and '5b76774cf78d7a3537006860fc78c00c191c9cb0'
2012-07-26 20:50:39 +00:00
kytv
00dd72e284 July 2012 GeoIP db update 2012-07-26 20:32:04 +00:00
kytv
05850371a6 Finnish, French, German, Spanish and Swedish translation updates from TX 2012-07-26 20:31:01 +00:00
sponge
c285cb84bd BOB Fix static references to Log 2012-07-26 20:30:42 +00:00
str4d
a4a0e1def3 Replaced a few more /home icons 2012-07-25 23:38:25 +00:00
sponge
fea7a42ece Reset spin flag in BOB 2012-07-24 18:38:36 +00:00
str4d
72f74b7f6e Disabled the iframe fallback for the summary bar
HTML compliance wins out over summary bar refresh for users with JS disabled,
for now - get user feedback after release.
2012-07-24 13:15:11 +00:00
str4d
a92456e144 Updated history.txt 2012-07-24 12:47:21 +00:00
str4d
7f7a82802d Added CC attribution for Creative Commons Cat 2012-07-24 12:07:09 +00:00
str4d
93097ab630 Moved RestartStatus back above LocalDestinations in default /home summary bar 2012-07-24 12:05:34 +00:00
str4d
d3d22a8f4b Added license for new /home icons 2012-07-24 05:32:40 +00:00
str4d
7a1b082216 Updated /home icon for git.repo.i2p 2012-07-24 05:18:20 +00:00
str4d
0e907c5ad0 Replaced 16x16 /home icons with 32x32 ones 2012-07-24 05:17:13 +00:00
str4d
59b8dc4f41 Update to dark console.css - more space efficient on /home, "0px" -> "0" 2012-07-24 03:23:51 +00:00
kytv
299109433c merge of '03b8e025ba8c54efe24644ee68500ae2ff0ea2de'
and 'b45f7b28764f452bbd5f58ebd598f465565cab5c'
2012-07-23 23:30:39 +00:00
zzz
9823d761d9 dont create router.ping file on Android to reduce flash wear 2012-07-23 23:21:20 +00:00
kytv
db6b8d3b6b debian: minor improvements to the build script
- Tighten setting of Debian version in I2P
- Ensure the clean target will remove .so and .o files
2012-07-23 23:20:23 +00:00
kytv
c61a18545e Debian: Use our Jetty/Tomcat libs instead of the ones from Debian/Ubuntu (for now at least).
Tomcat6 & Jetty6 are going to be dropped from the next release of Debian stable
(Wheezy) in favor of Tomcat7 and Jetty8.
2012-07-23 23:13:28 +00:00
zzz
c1181f855a remove unused dirs 2012-07-23 23:11:50 +00:00
zzz
e2aa2affd7 * LookaheadInputStream: Fix bug causing gunzip fails, esp. on Android
* SSLEepGet: Fix on Android (ticket #668)
2012-07-23 23:10:26 +00:00
str4d
7f18d25d0d Re-add alt="" to some icons in snark to prevent double text in text browsers 2012-07-23 21:49:30 +00:00
str4d
314817242b If the theme set for susimail doesn't exist, use the default instead 2012-07-23 11:01:39 +00:00
str4d
945a0f30aa If the theme set for snark doesn't exist, use the default instead 2012-07-23 10:39:11 +00:00
str4d
a7c8a7201a When fetching a theme, if theme config key is not found, write out the default
This is required in order to get the theme config keys of the various apps into
themes.config; this way, the routerconsole requires no knowledge of what apps
support universal theming, and can just blanket apply themes to all known keys.
2012-07-22 13:13:43 +00:00
str4d
6be94658a7 Use router console theme setting from themes.config in i2ptunnel 2012-07-22 11:33:20 +00:00
str4d
490dcc5020 Bugfix: update SnarkManager._theme each time getTheme() is called
FIXME: ensure that _theme is only read from the config file once per page load.
2012-07-22 06:59:43 +00:00
str4d
8e6bade42b Added checkbox to console to set theme universally across all apps 2012-07-22 06:53:43 +00:00
str4d
c145e4267c Fixes to light/console_ar.css 2012-07-22 00:18:07 +00:00
kytv
a4064190dd merge of '5aab7ebb6f496024fff1cc4b87e39475a7277db0'
and 'b2e508dbe3e9c7c67bb38d3f573481ae3fb8c9b3'
2012-07-21 20:59:01 +00:00
str4d
f97213630c Reverted susimail and snark links in /home and summarybar to point directly at app
The iframing pages remain accessible in the console, so this may be reverted in future,
or made configurable. The /webmail link buried in the text of the several readme.html
files has been left.
2012-07-21 20:57:46 +00:00
str4d
6a21e22bf1 Moved dark snark theme out of bundled themes dir due to an image issue
dr|z3d is happy for the problem image to be replaced and the theme reinstated
when universal theming support is added (likely 0.9.2)
2012-07-21 20:43:33 +00:00
zzz
77f8729257 new cowpuncher cert 2012-07-21 19:26:29 +00:00
zzz
39d4e1be72 SSU: Remove excessive exception creation (ticket #665) 2012-07-21 13:04:50 +00:00
zzz
ebe55aba61 remove dark as requested 2012-07-21 13:03:27 +00:00
str4d
3c4f1b7814 Store susimail theme setting in themes.config 2012-07-21 12:33:42 +00:00
str4d
ce024ff006 Store susidns theme setting in themes.config 2012-07-21 11:39:13 +00:00
str4d
e603b120c3 Store snark theme setting in themes.config 2012-07-21 11:06:24 +00:00
str4d
b17af505c2 Replaced a hard-coded string that was missed in previous commit 2012-07-21 10:22:12 +00:00
str4d
5d5a3b80e5 Store router console theme setting in themes.config 2012-07-21 10:11:32 +00:00
str4d
c8a73b63fd Added methods to read and write properties in arbitrary config files 2012-07-21 10:07:04 +00:00
kytv
ce7a46bbed Open Previewed http dests with target="_parent" in i2ptunnel
Before iframing i2ptunnel, clicking the Preview button would open the site in the parent
window. This change will cause the sites to open in the parent window from
within the iframed page.
2012-07-20 19:20:18 +00:00
kytv
eee67f09e1 en PO files updated and pushed to tx 2012-07-20 17:59:39 +00:00
str4d
ab7246565c Reverted alt tags in status column of snark 2012-07-20 04:16:53 +00:00
str4d
096d067d6c Updated history and bumped build version 2012-07-20 01:18:24 +00:00
str4d
9d2709be19 Update to light theme to increase top margin of iframes 2012-07-20 01:13:01 +00:00
str4d
3cce978e26 New light snark theme from dr|z3d (integrates well with light console theme) 2012-07-20 00:59:13 +00:00
str4d
8f30a74c7d Split up status and show/hide peers headings into separate columns 2012-07-20 00:57:53 +00:00
str4d
a86a2ba04a Moved text from headings in snark filemanager into tooltips (in line with main page)
Directory column could do with a different icon.
2012-07-20 00:36:43 +00:00
str4d
f4ffb30153 Added iframed fixes to default.css in classic, light and midnight console themes 2012-07-19 23:05:25 +00:00
str4d
ecdaa6f2b3 Removed text headings and status text from main snark page to reduce visual clutter
The header icons are self-explanatory (but tooltip also has header text); the
status text is available from the tooltip.
2012-07-19 21:39:17 +00:00
str4d
2b8b406f9d Added title and alt tags to Status and Torrent columns in snark main view 2012-07-19 13:06:45 +00:00
str4d
212a794c65 Give div.app fixed height for classic and midnight console themes
This stops app icons getting "stuck" on the right-hand side of /home
2012-07-19 00:41:52 +00:00
str4d
0e2dede168 Replaced itoopie with a dedicated icon for eepsite links on /home with no favicon 2012-07-19 00:08:29 +00:00
str4d
c1f3fa6004 Updates to dark susi themes and new light newsbullet from dr|z3d 2012-07-18 23:44:55 +00:00
str4d
e2be19039f Added missing git.repo.i2p and id3nt.i2p entries to hosts.txt 2012-07-18 12:33:30 +00:00
zzz
846f6f2190 * Home page: Add colombo-bt.i2p, remove keys.i2p
Icon created and contributed by colombo-bt.i2p
2012-07-18 12:00:42 +00:00
zzz
37716f34de * i2psnark: Clear rate stats when restarting torrent 2012-07-18 11:52:20 +00:00
str4d
f01ccf9797 Update to dark susimail theme from dr|z3d 2012-07-18 03:56:35 +00:00
str4d
074baa63f5 Fixed /home tooltip to not break page 2012-07-18 02:50:13 +00:00
str4d
763eb08dad Added git.repo.i2p and id3nt.i2p to /home eepsite list 2012-07-17 21:27:22 +00:00
str4d
1d40a88166 Fix snark Ajax JS (wrong level of escaping of quotes) 2012-07-17 20:55:36 +00:00
str4d
5766b36b33 Give the summary bar sections string names (some already translated) 2012-07-17 20:36:57 +00:00
str4d
4cea0b6099 US spelling 2012-07-17 19:44:44 +00:00
str4d
43fd5caf30 Fixed snark initAjax method so it runs (I'm SURE it did before...) 2012-07-17 19:32:22 +00:00
str4d
5c1a1b13f4 Update to dark susimail theme from dr|z3d 2012-07-17 12:22:52 +00:00
str4d
109e1a75bf Improved alignment of news headings in classic and midnight themes 2012-07-17 11:40:44 +00:00
str4d
99f8384129 merge of '9fdbbb81553e767812b7a8634edd867cb1ca8438'
and 'cc04809f72ea9e8f0e0427484d65f613838f65d7'
2012-07-17 10:56:51 +00:00
str4d
f3cb399605 Update to dark susidns theme from dr|z3d 2012-07-17 10:56:20 +00:00
str4d
c94ce79e68 Added links inside <iframe> tags on iframed pages to corresponding apps 2012-07-17 01:20:08 +00:00
str4d
744930a090 Consolidated Ajax calls for summary.jsi into a single summaryajax.jsi 2012-07-17 00:47:08 +00:00
str4d
be7aa991d7 Consolidated the common iframing JS into /js/iframed.js 2012-07-16 23:39:44 +00:00
str4d
c815bc2996 Removed spurious UTF8 chars from dark/console_ar.css 2012-07-16 21:36:48 +00:00
str4d
924520955e merge of '369340479baf15d01ba95519145edddba22634ca'
and '3b7088110cf55db67e72b7e9bfbf8cd832daac06'
2012-07-16 21:34:41 +00:00
str4d
0bff0a4998 Removed backup favicon.ico from css.jsi (all current themes have favicons) 2012-07-16 21:32:47 +00:00
str4d
691c003e95 merge of '762f90d57bd57a4e0b122dff85484774b0105d93'
and 'd02235b886c4e596e3c980dcb0b8df9d3547d103'
2012-07-16 21:29:04 +00:00
str4d
a28dab9bdc Bumped build number to -22 2012-07-16 21:04:11 +00:00
kytv
c33c0259a7 Only set extraversion in Unix since Windows doesn't have awk available
I need to investigate a cross-platform method.
2012-07-16 17:47:48 +00:00
str4d
77d40f8d31 propagate from branch 'i2p.i2p.str4d.fux' (head 48cafeb29fb3408078a8b93c0bab0fc9d766a8bc)
to branch 'i2p.i2p' (head 47f04ff21e8edd00134a0fd68219f86fd3caba36)
2012-07-16 16:17:19 +00:00
str4d
619b766c85 Removed CSS hiding susimail Cancel button (it might be hiding other buttons) 2012-07-16 16:13:03 +00:00
str4d
693ffed9be Updated history.txt 2012-07-16 16:11:03 +00:00
str4d
c175d5470f Updates to dark console theme from dr|z3d 2012-07-16 14:50:56 +00:00
str4d
42e6d06559 Whitespace fixes to dark susimail theme 2012-07-16 14:04:58 +00:00
str4d
25da127d02 Whitespace fixes for light susimail theme 2012-07-16 13:58:22 +00:00
str4d
00b88675ea Whitespace fixes in light susidns theme 2012-07-16 13:56:31 +00:00
str4d
c552db59e4 Whitespace fixes in dark susidns theme 2012-07-16 13:53:54 +00:00
str4d
763116fb24 Updates to dark susidns theme from dr|z3d 2012-07-16 13:50:21 +00:00
str4d
f3531f1c2c Updates to dark console theme from dr|z3d 2012-07-16 13:47:03 +00:00
str4d
a2a67d82ab Some updates to ieshim.css in classic theme to fix some IE console regressions 2012-07-16 13:44:58 +00:00
zzz
69cdcc8226 * XORComparator: Reduce object churn (Ticket #658) 2012-07-15 15:04:58 +00:00
str4d
5e11e51f6a Added "theme" to list of susidns config options 2012-07-15 13:13:57 +00:00
str4d
a419347eba Added preliminary dark susimail and susidns themes
Add "theme=dark" to susidns config page, or "susimail.theme=dark" to
susimail.config file, to enable the dark themes.
2012-07-15 11:03:51 +00:00
str4d
ab42e47385 Added iframing pages for susimail and susidns 2012-07-14 21:56:38 +00:00
str4d
50cfd52c23 Moved susidns CSS into themes dir (required moving loadConfig into BaseBean.java) 2012-07-14 06:27:23 +00:00
str4d
e0ff0c63c8 Moved susimail CSS into themes dir 2012-07-14 03:46:23 +00:00
str4d
a123def967 Inter-browser fixes for dark snark theme from dr|z3d 2012-07-14 01:38:14 +00:00
str4d
8360a2f4e7 Console theme hacks from dr|z3d to target specific Opera oddity 2012-07-14 01:29:04 +00:00
str4d
f13a1b2aed Tweak to snark dark theme from dr|z3d 2012-07-14 00:54:05 +00:00
str4d
cec5838649 Added newsbullets from dr|z3d to the other themes 2012-07-14 00:48:28 +00:00
str4d
2c0de05e9d Updates to dark console and snark themes from dr|z3d 2012-07-14 00:18:16 +00:00
str4d
f782afef8d Add scrollbar width to iframe height, so vertical scrollbar doesn't appear
FIXME: add horizontal scrollbar detection so only adding the extra height
when it is actually needed.
2012-07-14 00:13:33 +00:00
kytv
a45688867d Add README.Debian to the package
Previously, README.Debian use to be installed to /u/s/d/i2p. A while ago I
split I2P into smaller packages and symlinked /usr/share/doc/libjbigi-jni and
/usr/share/doc/i2p to /usr/share/doc/i2p-router. I didn't noticed that
README.Debian wasn't being included after the split, so now I'm explicitly
adding it.
2012-07-13 00:41:44 +00:00
kytv
6104cfa56a el & nl after poupdate
I nearly always run ant poupdate before checking in language files; I neglected
to do it for the last check-in.
2012-07-13 00:35:25 +00:00
kytv
6869ed937b Translation updates from tx
- Add Greek language
- Update Dutch translation
- Adjust flag rows
2012-07-13 00:28:06 +00:00
kytv
945cc55b54 move check for binary down since osx binaries are no longer 'fat' 2012-07-12 22:43:12 +00:00
str4d
7e7cabfdc2 Added getElementsByClassName shim for IE 2012-07-12 21:47:09 +00:00
str4d
cbd61e2fce Tweak to get rid of iframe scrollbars in dark snark theme 2012-07-12 14:21:37 +00:00
str4d
ffdac3ce2c Added some non-breaking spaces to error.jsp where JSP was eating the spaces 2012-07-12 13:40:54 +00:00
str4d
eaa64cb02f Removed superfluous "Updating:" from update status (section has a heading now) 2012-07-12 13:39:32 +00:00
str4d
b36a418dff More changes to dark snark theme from dr|z3d - close to RTM 2012-07-12 13:37:51 +00:00
str4d
46ca3ab51d Used JS changes to fix iframed i2ptunnel scrollbar issue in CSS
Also added comments to the JS to point out that the issue is that
offsetHeight doesn't include the very top or bottom margins.
2012-07-12 13:34:19 +00:00
str4d
0deaab7c1a Improvements to resizing JS in iframed app container pages 2012-07-12 13:07:48 +00:00
str4d
c6d45b22b6 Added links to iframed pages to open them in new tabs (as per old console) 2012-07-12 10:32:00 +00:00
str4d
69bcc9d012 Dark snark theme updates from dr|z3d 2012-07-11 21:47:50 +00:00
str4d
182409ce3a Corrected titles of iframed pages 2012-07-11 21:44:02 +00:00
str4d
c45dc0c838 Moved add and delete buttons into sidebar config table, and removed unnecessary ones 2012-07-11 21:20:35 +00:00
str4d
7d175678ab CSS for the sidebar config table from dr|z3d 2012-07-11 12:06:59 +00:00
str4d
dd86515d2e Tweaks to dark snark theme from dr|z3d 2012-07-11 12:02:58 +00:00
str4d
b1a4b8bfed Rearanged columns of summary bar config table 2012-07-10 23:35:54 +00:00
str4d
ac9bdab78e Added class to summary bar config table 2012-07-10 22:48:59 +00:00
str4d
177b6e2d48 Link both icon and text for tracker and magnet entries in snark torrent info 2012-07-10 22:48:07 +00:00
str4d
b48014f8e6 Use favicon from theme in I2PTunnel if it exists 2012-07-10 21:29:49 +00:00
str4d
f1881352c8 Further tweaks to ubergine and vanilla themes by dr|z3d for new layouts 2012-07-10 21:10:58 +00:00
str4d
d6572fd027 Give update status section a heading to draw attention to it, display total size 2012-07-10 21:07:36 +00:00
str4d
7e5edc2f6e Changes to snark themes from dr|z3d to work with new layouts
(and a tweak to dark console theme)
2012-07-10 19:30:42 +00:00
str4d
709c75c517 Reordered torrent info section in snark filemanager - reduced to 4 info lines 2012-07-10 19:03:48 +00:00
str4d
ebc4d53fa9 Corrected output of message to notice instead of error on summary bar config page 2012-07-10 12:05:07 +00:00
str4d
dbd95c5c64 Added extra column to keep ordering buttons in line 2012-07-10 11:57:40 +00:00
str4d
42565f19fc Use image buttons for ordering summary bar sections (images courtesy of dr|z3d) 2012-07-10 11:42:20 +00:00
str4d
8d9909acfb To improve themability, make torrent info table in snark filemanager a single column 2012-07-09 21:17:02 +00:00
str4d
9c7f9a935b Only add new summary bar sections to the bottom 2012-07-09 20:35:58 +00:00
str4d
c9fc3f11a6 Replaced text fields for ordering summary bar with movement buttons (CSS styling needed) 2012-07-09 07:59:41 +00:00
str4d
75046d11fb Separated disabling of iframe refresh from the refresh time 2012-07-09 00:39:52 +00:00
str4d
bb39d9ddcf Integrated summary bar preset buttons into main edit form as restore buttons 2012-07-08 22:11:05 +00:00
str4d
fb629404c6 Split torrent info and dir info on snark filemanager into two separate tables 2012-07-08 21:35:49 +00:00
str4d
78691ba344 Updates to dark console theme from dr|z3d 2012-07-08 12:07:54 +00:00
str4d
f41fde8471 Updates to dark snark theme from dr|z3d 2012-07-08 12:05:17 +00:00
str4d
319d217dc1 Slight simplification of class injection for iframed app pages 2012-07-05 13:04:45 +00:00
str4d
ec80501977 Remaining size in snark filemanager reads GB instead of Gbyte etc (consistency) 2012-07-05 13:01:00 +00:00
str4d
4a0319389b A few more newlines to improve HTML readability 2012-07-05 12:22:56 +00:00
str4d
ebcc304642 Fixed a few colspans that were missed when adding icon/thumbnail td 2012-07-05 11:49:36 +00:00
str4d
c695a51883 Tidy up layout of rendered HTML for one row of snark filemanager 2012-07-05 11:47:41 +00:00
str4d
3cc447c5f2 Put icon/thumbnail for snark filemanager in separate td 2012-07-05 11:36:10 +00:00
str4d
52742ceeca Moved "View or change bandwidth" link inline to tidy up vertical alignment 2012-07-05 02:55:28 +00:00
str4d
08d86019e4 Uncommented input.default CSS (to hide extra Add button) in dark snark theme 2012-07-05 02:50:01 +00:00
str4d
582a62d75b Added classes to and removed hard-coded layouts from snark config page (stubbed in CSS) 2012-07-05 02:48:45 +00:00
str4d
8ebadf5236 propagate from branch 'i2p.i2p' (head 5b24a07e8a843d03ea45e664c59b93937c5efc42)
to branch 'i2p.i2p.str4d.fux' (head 0bfff6086d6f72df836909ae379a95ebbe4b6933)
2012-07-05 00:48:41 +00:00
str4d
814f5ca194 Arabic-specific console theming for dark from dr|z3d 2012-07-05 00:36:32 +00:00
str4d
3da63182cd Updates to dark snark theme from dr|z3d 2012-07-05 00:35:09 +00:00
str4d
029a903d79 Expanded resizeFrame() to prepare for more intelligent iframe-sizing 2012-07-04 12:49:54 +00:00
zzz
e2588a5379 move DecayingBloomFilter, DecayingHashSet, and xlattice filters from core to router 2012-07-02 19:22:33 +00:00
zzz
0d8bcd5dad * i2psnark:
- Don't send a keepalive to a peer we are going to disconnect
   - Disconnect peer when idle a long time
   - PeerCheckerTask cleanup
   - Static ref cleanup
   - Don't show a downloaded torrent file as "seeding"
   - Better torrent file download icon (from Silk, same license as the others)
2012-07-01 16:16:08 +00:00
zzz
63f22a54e1 fix unsafe initialization of super constructor calling override 2012-06-29 17:21:57 +00:00
zzz
ab18550711 * Update: Increase eepget timeouts to reduce retries 2012-06-29 16:25:22 +00:00
zzz
4092f61898 * Streaming:
- Allow at least 3 packets and up to half the window to be active resends
     instead of just 1, to reduce stall time after a packet drop
   - Increase fast retransmit threshold back to 3 to reduce retransmissions
   - Don't fast retransmit if we recently retransmitted it already
   - Allow double the window as long as gaps are less than the window
   - Don't set the MSS in a resent packet (saves 2 bytes)
   - Remove redundant calls to updateAcks()
   - Update activity timer when resending a packet
   - Reset unackedPacketsReceived counter at all places where acks are sent
     so it isn't wrong
   - Fix some places where the activeResends count could become wrong
   - Prevent storm of CLOSE packets
   - Never resend the whole packet in ackImmediately(), just send an ack
   - Cancel flusher timer in MessageOutputStream when closed
   - Move some createRateStats to ConnectionManager to reduce repeated calls
   - Cleanups, javadocs, logging, volatile, finals
2012-06-29 14:53:53 +00:00
zzz
ebb6609a2b fix SimpleTimer logging 2012-06-29 14:05:39 +00:00
str4d
820345f84d Changes to dark theme from dr|z3d to improve look of tunnel wizard 2012-06-29 13:49:37 +00:00
zzz
5a1d52d82c * HTTP Proxy: Change the error code for unknown host from 404 to 500. 2012-06-29 13:30:24 +00:00
str4d
9adb97d300 Tweak to dark console theme .iframed .panel margins 2012-06-28 03:36:31 +00:00
str4d
eae4d704a1 Copied body.iframed CSS from dark i2ptunnel.css to dark snark.css 2012-06-27 03:26:22 +00:00
str4d
84cc6711b4 Dark theme for i2psnark from dr|z3d - for better integration with router console 2012-06-27 03:19:30 +00:00
str4d
5be02b1592 Fixed JS for iframed apps so the CSS class is injected on page change 2012-06-27 02:16:21 +00:00
str4d
255894e241 Embed /i2psnark/ in an iframe like /i2ptunnel/ 2012-06-27 02:00:30 +00:00
zzz
6c8c87b2dd javadocs 2012-06-25 19:29:51 +00:00
zzz
dba3fee477 - Concurrent PeerCoordinatorSet
- final infoHash in Snark
2012-06-25 18:20:18 +00:00
zzz
50fba8fc8d propagate from branch 'i2p.i2p' (head db152f1a9e08e80c7bd3b87735b51800e8f4c46f)
to branch 'i2p.i2p.zzz.dhtsnark' (head 9b08b2f47961167d0fee52b6481895c494d410d6)
2012-06-24 19:53:20 +00:00
zzz
5eab417134 propagate from branch 'i2p.i2p' (head db152f1a9e08e80c7bd3b87735b51800e8f4c46f)
to branch 'i2p.i2p.zzz.test' (head 5fd7a423338073ff81f5118cde74317b567846a6)
2012-06-24 19:53:08 +00:00
zzz
ff0bfb9f12 * i2psnark: Don't create a new PeerCoordinator after restart, as the
TrackerClient holds on to the old one and that causes it
             to not get peers. Possibly fixes ticket #563.
2012-06-24 19:26:23 +00:00
zzz
1671e3b126 Fix bad size estimate when tags are included in the AES block,
resulting in trailing zeros after the random padding in the unencrypted AES data block.
The number of zeros equaled the number of tags included (typ. 6 or 40).
As the data size is rounded up to the next multiple of 16,
this increased the size of the data by 0, 16, 32, or 48 bytes when tags were included.
Bug introduced 2004-10-30.
2012-06-24 19:23:05 +00:00
zzz
fe53501990 * GarlicMessage:
- Put data clove last to speed acks and leaseset store on far end
  - Change release target
  - Javadocs and cleanups
2012-06-24 14:41:50 +00:00
zzz
e497859587 * ElGamal/AES/SessionTag:
- Increase TX expire from 10 to 12 min, while keeping RX expire at 15 min.
    3 minutes should be plenty of clock skew + delay.
  - Move tags-to-send and low-threshold values to be per-SKM
  - New session config options crypto.tagsToSend and crypto.lowTagThreshold
  - Prep for per-packet override of tags and thresholds
  - Cleanups and Javadocs
* I2PTunnel: Add some defaults for the new session config options
* OCMOSJ:
  - Don't bundle LeaseSet just because we're requesting an ACK
  - Changed session config option shouldBundleReplyInfo to default to true
    and be used to disable bundling altogether when set to false.
    Was previously an undocumented option to force bundling with a certain probability.
  - Don't send tags unless we've already generated a reply token (race)
  - Cleanups and Javadocs
2012-06-24 13:17:52 +00:00
zzz
97b05b1dbf * I2PTunnel: Fix NPE on shared client creation, thx kytv
* Transport: Add Ethiopia to hidden mode list
 * Log and javadoc tweaks
2012-06-24 11:38:37 +00:00
str4d
588799a2ff Update to dark theme from dr|z3d 2012-06-24 01:15:06 +00:00
zzz
d5a1e0b1c6 - Add kad lib, from i2p.zzz.kademlia branch (without the history),
which is a rewrite of the netdb kad
- Drop now-unused SHA1Comparator
- Efficiency tweak to NodeInfoComparator
2012-06-22 17:39:41 +00:00
zzz
5883b7344e propagate from branch 'i2p.i2p' (head 80aed456e1c6e4b17906153c9ee6dc9bc45e0eec)
to branch 'i2p.i2p.zzz.dhtsnark' (head dbf88ff4c1429f26656ad34fe0b9ba94305d726a)
2012-06-22 15:13:04 +00:00
zzz
8522779df1 - Switch to real kad with lib from i2p.zzz.kademlia (not checked in yet)
- Bootstrap only once in explore thread
- Add exploring to explore thread
- Don't store default DHT setting in config file, so we can switch default to true later
- Add new enforce-protocol streaming config, sorry locks out < 0.7.1 peers
- Log tweaks
2012-06-22 15:12:43 +00:00
str4d
7976ba1dff Only display summary bar "Show news" link on /home (/console already has one) 2012-06-22 01:32:07 +00:00
str4d
e88ca3048c Removed unnecessary extra sentences from summary bar tooltips 2012-06-22 00:08:43 +00:00
str4d
8412bafc5c Use JS injection to allow iframe-specific I2PTunnel styling 2012-06-21 23:47:49 +00:00
zzz
2a8adcb89a * IRC Client: Don't flush output unless out of input, so the
streaming messages don't get split up unnecessarily
2012-06-21 21:16:54 +00:00
zzz
829e3f47ff Store context in the PeerSelector so we don't have to pass it around 2012-06-21 20:52:39 +00:00
zzz
4e4634496a * TunnelPool: Fix bug where a tunnel was marked as reused when it wasn't 2012-06-21 20:26:29 +00:00
zzz
d148efd458 * TunnelPoolManager: Use one ClientPeerSelector for all pools 2012-06-21 20:08:02 +00:00
zzz
f7656b0401 * TunnelInfo: Change msg counter from long to int 2012-06-21 19:59:29 +00:00
zzz
6635448bda * I2CP: Make separate message ID counters per-destination, use atomic,
increase max (could have caused "local loopback" problems)
2012-06-21 19:52:00 +00:00
zzz
baa89c5bbf * OCMOSJ, ElG, Streaming: log tweaks 2012-06-21 19:10:14 +00:00
str4d
ab1144865f propagate from branch 'i2p.i2p' (head 204c786941e233e9ed0e447499049f5c21103f40)
to branch 'i2p.i2p.str4d.fux' (head 5bc2b4f4713087086e44eca6678d880651fa717a)
2012-06-21 04:05:48 +00:00
str4d
4348ff2689 Added custom bullet to newsheadings li 2012-06-21 01:54:28 +00:00
str4d
33c4b321db Fix up alignment of news headings in other themes 2012-06-20 12:56:00 +00:00
zzz
39d9a25e19 log tweak 2012-06-20 12:22:43 +00:00
zzz
b5dad73f6f * I2PSession:
- Greatly simplify the VerifyUsage timers
   - Constructor cleanup
2012-06-20 12:18:57 +00:00
str4d
99eb49e347 Added favicons to resident themes (dr|z3d's dark favicon for dark and midnight themes) 2012-06-20 02:55:44 +00:00
str4d
11f111790e Use a theme-specific favicon.ico if it exists 2012-06-20 02:48:24 +00:00
zzz
f8e470c7f4 propagate from branch 'i2p.i2p' (head a38c8874bc61e9bf11c4d43666ad72cd5eecbf8a)
to branch 'i2p.i2p.zzz.dhtsnark' (head 028e93195ce28c8b6fbe573e6c660d5c329df42a)
2012-06-20 01:19:25 +00:00
zzz
d8a2e39006 from last checkin - fix enforce proto default, fix http client delayed start 2012-06-20 01:19:05 +00:00
zzz
c6d1c552f8 propagate from branch 'i2p.i2p' (head 9ca94e960929c6af5dea1085105278d2f33217f2)
to branch 'i2p.i2p.zzz.dhtsnark' (head 1f23a71b0fa5169c220f3f21dd705e1fcfbb1b5d)
2012-06-19 23:31:53 +00:00
zzz
e383477b01 * Socks: Pass remote port through
* I2PTunnel: More javadoc warnings on default options
2012-06-19 21:48:31 +00:00
zzz
129b16d93d * Streaming:
- Listen only on local port if set
   - Listen only for streaming protocol if configured (new option)
   - Javadocs re: ports
2012-06-19 20:26:46 +00:00
zzz
48f29ff1b8 - Hide buttons while stopping all 2012-06-19 20:24:30 +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
d368937bce dash sixteen 2012-06-18 21:40:05 +00:00
zzz
4b3ccabb44 - Thread task to open tunnel and improve UI feedback while open is pending 2012-06-18 21:07:34 +00:00
zzz
4dcfe3e434 * i2psnark:
- Improve torrent shutdown handling to maximize chance of
     announces getting to tracker
   - Clean up delete-torrent messages
   - Remove redundant shutdown hook
   - Avoid NPE in PEX message handling
   - Log tweaks
2012-06-18 18:06:47 +00:00
zzz
273d7399a0 jump table tweak 2012-06-15 01:30:58 +00:00
zzz
5ce0479268 tweaks 2012-06-15 01:29:29 +00:00
zzz
de3ce6cdb7 handle jump servers with ports 2012-06-14 22:08:40 +00:00
zzz
3e192cc57e remove text about restart 2012-06-14 22:07:28 +00:00
zzz
6c5902837c * NetDB: Only publish stats every so often, to improve
anonymity while preserving the ability to monitor
          the network (effective next release)
2012-06-14 19:48:12 +00:00
zzz
e522ffad4e * I2PTunnel:
- More client options cleanups
   - Options changes now propagate to running
     socket managers and sessions, and through to the router
 * SocketManager:
   - Simplify factory, use 4-arg constructor,
     make fields final, deprecate 0-arg constructor
   - Improve how options are updated
   - Javadocs
2012-06-14 19:44:47 +00:00
zzz
64221fb3fb * I2PSocketEepGet: Use specified port
* I2PTunnel:
   - Don't strip port from an I2P URL
2012-06-14 19:42:07 +00:00
zzz
c73044b6b4 * Streaming:
- Channel cleanups and comments
   - New I2PSocketAddress
2012-06-13 19:08:49 +00:00
zzz
ad1b356879 * i2psnark: Possible fix for piece-after-choke 2012-06-13 19:04:11 +00:00
zzz
07caf2e316 * I2PSocketEepGet: Set port to 80
* I2PTunnel:
   - Pass port through HTTP client proxy
   - HTTP server proxy sets host header to
     the value of "spoofedhost.xx" option for port xx
   - Set client options more efficiently
2012-06-13 19:02:09 +00:00
zzz
c2137a2a80 - Add explore thread
- More checks for stopping
- Add xor of port to secure NID
2012-06-12 21:38:25 +00:00
zzz
44da37f009 - Timeout if can't find b32
- Refactor ReplyWaiter
2012-06-12 19:22:31 +00:00
zzz
d0b967388a rework DHTNodes to hide the CHM implementation, in prep for real Kad 2012-06-12 18:30:58 +00:00
zzz
41096c7f23 - Add heardAbout() and call for receive peers
- Move last-seen tracking from NodeInfo to NID, add fail tracking
- Make NodeInfo fields final
- Remove nodes on consecutive failures
- Only persist nodes heard from recently
- Implement NID verification for security
2012-06-12 18:09:42 +00:00
str4d
4f6fb6993d Pass requestURI through to xhr1.jsp so forms work and correct summary bar is chosen 2012-06-12 00:12:51 +00:00
str4d
fa3e3e0764 Enforcing minimum refresh rate better, and reducing it to 3 seconds
This does mean that the iframe don't-refresh state (= refresh rate of 0 seconds)
doesn't hold if the page is changed (in fact, the refresh rate becomes the
minimum) - so maybe better to have a different config var for that?
2012-06-11 23:33:33 +00:00
zzz
fe2b97c941 propagate from branch 'i2p.i2p' (head 27fc588723d201c76ea9c18a6c715b11efcb5b0e)
to branch 'i2p.i2p.zzz.dhtsnark' (head cae6d265415ba9ed4242b3fc888ffcf2a1c1b2f2)
2012-06-11 20:29:19 +00:00
zzz
6e52ae307c * Router: Don't let shutdown tasks hang the shutdown 2012-06-11 20:09:31 +00:00
zzz
6e077ee621 * i2psnark:
- Reduce TrackerClient threads
   - Reduce delay between peer adds for faster startup
   - Thread the announces and reduce timeout when stopping
2012-06-11 19:38:33 +00:00
zzz
30e2f73d5f * i2psnark:
- Display torrent file downloads in torrent area
   - Sort magnets and downloads first
   - Fix sorting problem when torrent dir is a symlink
   - Reduce max file idle time
   - arrow_down icon copied from console css
2012-06-11 12:04:40 +00:00
zzz
7469e9c63d * NativeBigInteger: Workaround for Raspberry Pi to load the correct lib 2012-06-11 11:48:34 +00:00
str4d
296ddbe930 Removed some unnecessary <hr>s 2012-06-11 05:32:53 +00:00
str4d
e20f2d0bf6 Summary bar for /home defaults to reduced preset, everywhere else to full preset 2012-06-11 05:29:27 +00:00
str4d
cc61f4eb61 Some changes to enable per-page sidebar configuration from the config file 2012-06-09 13:48:26 +00:00
str4d
0a61b8052c propagate from branch 'i2p.i2p' (head 44d553e8644f01d5e5af3c3145210bdb0a923d3c)
to branch 'i2p.i2p.str4d.fux' (head 51022349e906bd393602b558861bcaaac4d56c89)
2012-06-09 06:11:40 +00:00
str4d
cbcbfea6e8 Shorten /i2ptunnelmanager to /i2ptunnelmgr (/i2ptunnel is surplanted by /i2ptunnel/) 2012-06-09 06:08:44 +00:00
str4d
57abfe7653 Set position: absolute for div.routersummaryouter so /home app icons don't clear past it 2012-06-09 04:33:29 +00:00
zzz
e0313814b8 disable private config for default trackers 2012-06-08 16:39:10 +00:00
zzz
59df524a91 * i2psnark:
- Move private tracker config from create box to torrent config
   - Refactor private and open tracker configuration
   - Add private indication on details page
2012-06-08 16:11:55 +00:00
zzz
b304393bc3 * netdb.jsp: Don't show our info on summary page since there's a tab for it now 2012-06-08 16:10:26 +00:00
str4d
f6304ccd4d Commented out "All times are UTC" blurb because all graphs are labeled UTC 2012-06-08 12:58:50 +00:00
str4d
9d241cc0d4 Added tooltips to the various sections of the summary bar 2012-06-07 14:14:13 +00:00
str4d
a46ca210f5 Added some spaces to notification messages on /configsidebar 2012-06-07 11:11:37 +00:00
str4d
328857f97f Tweaks to config nav bar in dark theme from dr|z3d 2012-06-07 10:39:14 +00:00
str4d
b00fbfa23d Centre box for order of new section, and add default value 2012-06-07 10:26:44 +00:00
str4d
3a75f8d7d1 Modifying section addition to show an option list
Also adding form handler class that I forgot to commit earlier.
2012-06-07 04:42:52 +00:00
str4d
84344b6789 Added a config page for summary bar 2012-06-07 02:51:22 +00:00
str4d
b75d28fd0d Added /i2ptunnelmanager which wraps /i2ptunnel/ in an IFrame
/i2ptunnelmanager redirects to /i2ptunnel/ if the browser doesn't support IFrames.
2012-06-05 15:19:40 +00:00
str4d
a8424e59b0 propagate from branch 'i2p.i2p' (head ab5f37b28e499d49e108e8e6869164d107c7049e)
to branch 'i2p.i2p.str4d.fux' (head fb4425cd3e38762f211f73d91c7a173972e7145c)
2012-06-05 13:38:02 +00:00
str4d
420bf851b5 Added Ajax script to every routerconsole page that includes summary.jsi 2012-06-05 13:37:10 +00:00
str4d
83c8233812 Insert routerconsole.summaryRefresh config value into Ajax script
This way, both Ajax and IFrame get their refresh time from config (though
IFrame one can still be modified live).
2012-06-05 13:00:40 +00:00
str4d
52a3860717 Rearrange summary bar code to consolidate Ajax and IFrame, and /home and /console
Now, Ajax will be used first, and will fall back to IFrame if JS is disabled,
and a separate page if on a text or mobile browser.
Also, /home and /console (and everywhere) now all have the same summary bar
content, which currently defaults to the original full listing.
2012-06-05 12:44:17 +00:00
str4d
531c6c0f4c Implementation of customisable summary bar via routerconsole.summaryBar property
The initial attempt using mapping of strings to methods is shorter and neater,
but also doesn't work so is commented out.
2012-06-05 07:36:24 +00:00
str4d
5699b4515b Preparations for making the summary bar customisable 2012-06-05 02:12:30 +00:00
zzz
6a1b90f8f8 hash caching 2012-06-05 01:03:39 +00:00
str4d
ceedc9c645 Moved rendering of news headings into SummaryBarRenderer
An instance of NewsHelper needs to be passed in to get output.
2012-06-04 23:46:03 +00:00
zzz
3f40487c99 - Add persistent local DHT storage
- Shutdown now closes tunnel
- Delay after sending stop announces at shutdown
- Stub out using Hash cache
- Implement stop for all cleaners
- Log tweaks
2012-06-04 22:34:56 +00:00
zzz
a6f7761544 propagate from branch 'i2p.i2p' (head ab5f37b28e499d49e108e8e6869164d107c7049e)
to branch 'i2p.i2p.zzz.dhtsnark' (head afa1bbfb0882c9c1946ec32b87300e127c9928b2)
2012-06-04 14:26:10 +00:00
zzz
e1c9cd6cdc * i2psnark: Take tracker out of opentracker list when removed 2012-06-04 14:25:53 +00:00
zzz
d5cb443925 - Switch back from storing NID to full NodeInfo for outgoing tokens so they don't get expired early
- Announce only to the single closest DHT peer
- Increase random port range
- Decrease max local tracker and DHT size
2012-06-04 14:15:38 +00:00
str4d
9333cd56f9 Moved calls to external renderers into separate methods to match the rest 2012-06-04 13:28:52 +00:00
str4d
910001e3a1 Split HTML rendering of summary bar into separate methods
This solidifies the summary bar design pattern of modular sections separated by
<hr>s which in future could be reordered or hidden without affecting the theme.
2012-06-04 13:10:12 +00:00
zzz
121491a3be - B32 lookup if required for non-announce queries only
- Token timeout tweaks
- Most classes package private
2012-06-03 16:05:38 +00:00
zzz
152b2152cb - Fix node ID / node info confusion
- Fix updating node ID when receiving pong
- Fix getting DHT enable setting from config file
- Fix handling of get_peers replies
- Fix sending and receiving announces without signing
- Fix incoming/outgoing token handling
- Set cleanup timer for all queries
- More debug logging
2012-06-03 15:25:51 +00:00
kytv
0abbe45a6d correct flag country (I copied the line and changed all but the flag) 2012-06-03 15:02:27 +00:00
kytv
403d6a322a Italian language updates from tx & debconf updates
-10
2012-06-03 14:34:39 +00:00
kytv
4ec20ef796 typo fix (*facepalm*) 2012-06-03 14:09:41 +00:00
kytv
3b7eaa107e s/$ENGLISHNAME/$NATIVENAME/g 2012-06-03 13:52:27 +00:00
kytv
8375e9129d enable Hungarian in another spot 2012-06-03 13:46:33 +00:00
kytv
53fbece6b5 Hungarian language translation by AdminLMH from TX
Thanks!
2012-06-03 13:46:07 +00:00
str4d
69d909d3eb Added <hr>s to separate the various logs on /logs 2012-06-03 00:22:03 +00:00
zzz
4346c90aa2 lower log level 2012-06-02 21:45:00 +00:00
zzz
f8c185d09f prep for merging 2012-06-02 21:44:23 +00:00
zzz
558bb2f4f3 select proto on UDP send 2012-06-02 18:56:10 +00:00
zzz
7b07eb89a3 - Uncomment DHT
- Change DHT from option bit to extension message
- Add DHT start/stop code
- Add UI for DHT enabling
- Add raw datagram protocol type and use for response port
2012-06-02 18:52:46 +00:00
zzz
bec33cad87 propagate from branch 'i2p.i2p' (head f005cd64cce03cf3a301359f94380bc20eaa7c61)
to branch 'i2p.i2p.zzz.dhtsnark' (head 0562e4f429dcebf3f623d0975bd3a63d7645c0b7)
2012-06-02 15:16:14 +00:00
zzz
eb6217add9 add failsafe check for job queue sort order 2012-06-02 13:49:38 +00:00
zzz
7d94f9fb19 improve opentracker configuration 2012-06-02 13:49:14 +00:00
zzz
324e9c960d fix partially-complete torrent not announcing 2012-06-01 14:12:32 +00:00
zzz
96575e61f2 * Console: Tab the netdb and profile pages 2012-06-01 13:30:38 +00:00
zzz
8d57cba762 * NetDB: Reduce flood redundancy from 8x to 6x 2012-06-01 13:27:53 +00:00
zzz
e1823ece68 whitespace fix 2012-06-01 13:27:01 +00:00
str4d
b23414eab1 Reordered /home summarybar, added <hr> after update download button 2012-06-01 01:21:57 +00:00
zzz
38a4f05000 * i2psnark:
- Close connection immediately if bad protocol,
     this makes blacklist work better too
   - Stop adding peers when we hit the limit
   - Lower limit for outbound connections so we give
     new peers a better chance in large swarms
2012-05-31 15:20:50 +00:00
zzz
041c87a2c9 * i2psnark:
- Add per-hour conn limit
   - Blacklist peer after two bad handshakes
   - Reduce connect timeout
2012-05-31 12:19:27 +00:00
str4d
ef06fc758c Show news headings in the /home sidebar when the main news div is hidden
Note: this now refreshes along with the rest of the sidebar, so the news.xml
file is read once every 15s - it may be better to cache the headings somewhere,
though it's debatable whether reading the cache file is better than reading the
news.xml file...
2012-05-31 09:30:30 +00:00
kytv
9f1c95c829 rework patch to deal with my earlier changes to jcpuid's build.sh 2012-05-30 20:42:06 +00:00
zzz
f14ff31a20 * Timestamper:
- Move from core to router, leave stub in core
     so it doesn't break compatibility. This removes a
     thread in app context and prevents any app context from
     running NTP; external clients must use the time
     received from the router.
   - Increase query interval
2012-05-30 20:03:30 +00:00
zzz
ddc329e8f1 Handle URI encoding, UTF-8, and multiple trackers in magnet links 2012-05-30 19:45:45 +00:00
zzz
8453c34bfc Improve rarest-first behavior by not favoring a partial piece
held by multiple peers when requesting from a seed
2012-05-30 15:21:37 +00:00
zzz
c6fcdf967c increase per-minute conn limit from 6 to 8 2012-05-30 14:10:03 +00:00
zzz
1427c502c0 Reduce log level to warn for normal EofException when generating graphs 2012-05-30 14:09:16 +00:00
zzz
4e84370128 Increase max upstream form field to 4 digits (9999) ticket #645 2012-05-30 14:06:45 +00:00
zzz
5314d886be merge of '539c9ff2992eb584e2c311924370437f167f0b99'
and 'b355f1862601a6a192c42f1f50743f2a4f0b4c22'
2012-05-28 22:20:19 +00:00
zzz
829af21c49 javadoc fix 2012-05-28 18:04:11 +00:00
kytv
c9406b8f96 document changes for Arch 2012-05-28 17:01:31 +00:00
kytv
af398632f3 Add initscript support to i2prouter for ArchLinux
With this commit, ArchLinux users can run "i2prouter install" to install an
initscript to /etc/rc.d.
2012-05-28 16:59:47 +00:00
kytv
e574b5e61a minor updates to jbigi/jcpuid scripts
- use my find-java-home stub script when building jcupid
- move find-java-home to core/c
- add support for ArchLinux to find-java-home
2012-05-28 16:56:08 +00:00
HungryHobo
d946fda859 Replace reseed host i2pbote.net with euve5653.vserver.de (http://trac.i2p2.i2p/ticket/445) 2012-05-26 07:25:44 +00:00
kytv
df3771e791 merge of '60890b0ffbf109b297bd6dd66a28d8179322331a'
and '7e63908db8b78229f8f0c963050b062ce0f6dd96'
2012-05-25 21:09:25 +00:00
zzz
df00725077 compile fixup after merge 2012-05-25 20:30:06 +00:00
zzz
26846d592c merge of '10bd7656ab9a474e3bb2d405d50261f147690ce4'
and 'c3f96ef85962a5e9a3896e117036cc83b37fe3a8'
2012-05-25 20:11:28 +00:00
zzz
21466e017f explicit merge of 'dd3f93f7ec59e6a7f967945a75c5d4d7b53539ed'
and 'e99d32aef6da4112890ebe09c3f7d8fcb8b647e5'
2012-05-25 19:55:02 +00:00
zzz
b033db969c Revert all changes to the org/cybergarage library
in the 2009-08-11 whitespace cleanup at ef1c23821d433903124f7612cbc46ac096fc985b
to make merging with the newer library easier.
2012-05-25 19:52:39 +00:00
zzz
d18e4d430c explicit merge of '59eae97dbb470d8c4a1e4dba3a9763e134bb0c53'
and 'aeec86a504a5fd67dff12d6775411a9c865d42ad'


Merge to aeec86a504a5fd67dff12d6775411a9c865d42ad
which is just before the 2009-08-11 whitespace cleanup at ef1c23821d433903124f7612cbc46ac096fc985b
2012-05-25 19:36:22 +00:00
zzz
14ac5ac03e Cyberlink for Java v2.1 (2011-09-16) from SVN,
with extra parsers in xml/parsers removed.
Diverging from original v1.7 checkin in prep for merging.
2012-05-25 17:47:18 +00:00
kytv
464279ca1c German, Spanish, and Swedish translations from Transifex 2012-05-25 12:40:12 +00:00
kytv
6014de9cd5 Italian translation updates from Transifex (thanks colombo-bt!) 2012-05-25 11:05:22 +00:00
str4d
e7c3e07626 A few more CSS changes to finish tweaking /home.jsp for the other themes 2012-05-25 05:27:46 +00:00
str4d
c4057bb5a0 A few trivial CSS changes to get /home.jsp looking better with the other themes 2012-05-25 01:27:48 +00:00
str4d
34f0420753 Changes to dark theme
- improve /home.jsp
- general theme tweaks and fixes
2012-05-25 00:58:29 +00:00
str4d
10bd1343c3 Changes to structure of /home.jsp to bring it back in line with /console.jsp 2012-05-25 00:43:29 +00:00
zzz
4979f8dace - Custom tracker map AIOOBE fix, thx kytv 2012-05-23 22:40:03 +00:00
zzz
b2846de94f propagate from branch 'i2p.i2p' (head 8066e0ff00b526c6971e77de44ff2d322f25069a)
to branch 'i2p.i2p.zzz.dhtsnark' (head f857dd921a7c806c85eb80419f4f9fdd3b6428a2)
2012-05-23 16:56:13 +00:00
zzz
501f2f85d5 * jobs.jsp: Add more queue diagnostics 2012-05-23 16:37:43 +00:00
zzz
580bb5a6fe * i2psnark:
- Fixes when complete except for skipped files
     (ticket #447) status in UI, don't connect outbound,
     disconnect seeds when done
   - More classes pkg private
2012-05-23 16:36:37 +00:00
zzz
e27df771aa - Fix deadlock when changing file priorities 2012-05-22 19:26:37 +00:00
zzz
0f321f1597 - Refactor tracker map 2012-05-22 18:19:52 +00:00
zzz
10872f751e - Prevent torrent shutdown when changing file priority to skip 2012-05-22 18:18:30 +00:00
zzz
20567ae75e * RoutingKeyModifier: Update after large clock shift 2012-05-22 18:16:51 +00:00
zzz
f06d99480d javadoc fixes 2012-05-21 12:53:56 +00:00
zzz
c2e39687e6 * RoutingKeyModifier: Several changes to ensure the routing key
is correctly changed just after midnight.
2012-05-20 18:20:48 +00:00
zzz
6972d9d02b change stat name, log tweak 2012-05-20 18:18:58 +00:00
zzz
d8b3d2c508 * i2psnark:
- Create sparse files at torrent creation and delay
     "ballooning" until first write (ticket #641)
   - Redo clear messages button
   - Concurrent message queue
2012-05-20 18:15:36 +00:00
zzz
1da1dce981 * Profiles: reduce same-country bonus 2012-05-20 18:13:11 +00:00
zzz
c4f9485e13 * Console: Add full file path to thread dump message 2012-05-20 18:12:41 +00:00
zzz
9cff4d5a42 final 2012-05-20 18:12:20 +00:00
zzz
6ca4b519bf * i2psnark:
- Store received chunks in temp files
   - Don't allocate from heap for unneeded chunks
   - Remove peer count restriction for torrents with large pieces
   - Use priorities and rarest calculations to sort partials
   - Preserve p parameter in clear messages link
2012-05-19 13:27:02 +00:00
zzz
3685bf04d0 add X-Frame-Options to console headers 2012-05-13 13:05:17 +00:00
zzz
fc5e30e6ae better throttle log msgs 2012-05-09 21:07:33 +00:00
zzz
047c668ee1 dont include wrapper .txt files in installer 2012-05-09 21:06:59 +00:00
zzz
e55a1f608a comment out unused text summaries 2012-05-09 21:05:34 +00:00
kytv
cbbf82a4ae Stricter match by matching 'Version:' 2012-05-09 02:18:20 +00:00
kytv
81d9e2f164 update changelog 2012-05-06 10:36:22 +00:00
kytv
8397296286 Add 'graceful' / comment out stanza not needed on Ubuntu 2012-05-06 10:35:59 +00:00
kytv
06d0412558 Spanish & German translation updates from transifex
(These were sent to transifex too late to make it into 0.9)
2012-05-05 20:30:08 +00:00
kytv
ffde067c5e s/Reunion/Réunion/ 2012-05-05 16:00:37 +00:00
zzz
c4a05ec49e add missing wrapper.jar to installer-nowindows 2012-05-02 13:14:44 +00:00
zzz
ed92411df2 installer target fixes 2012-05-01 23:41:04 +00:00
zzz
7a690b245f rename windows installer; 0.9 2012-05-01 21:06:17 +00:00
hiddenz
7af65f4346 Update russian translation 2012-04-29 17:31:24 +00:00
str4d
c89e127d8a Added missing test classes to net.i2p.data.i2cp 2012-04-27 03:00:45 +00:00
str4d
104bfa8784 Exclude TestSuite classes from testing 2012-04-27 02:45:00 +00:00
str4d
3013b56d16 Fixed server tunnel wizard bug - pass a value for privKeyFile 2012-04-26 23:01:12 +00:00
kytv
188316132e refer to translation updates 2012-04-26 18:37:18 +00:00
kytv
53c7f7d602 use our jstl.jar instead of glassfish 2012-04-26 18:19:48 +00:00
kytv
3ccc102412 German, Spanish, and Swedish translation updates from Transifex 2012-04-26 18:19:07 +00:00
str4d
e99749097a Moved tests for net.i2p.data.i2cp into the correct subdirectory 2012-04-26 12:08:14 +00:00
zzz
9d1995125a xml fix 2012-04-21 14:43:51 +00:00
kytv
b18f654e37 look for ^# so there aren't surprises later (thanks for pointing it out, darrob!) 2012-04-20 20:14:59 +00:00
kytv
a70d9394da pushed to tx after fixing the bundle-messages script 2012-04-20 19:11:58 +00:00
kytv
6eff7be49a Avoid catching comments in countries.txt 2012-04-20 18:09:40 +00:00
zzz
01efcd3156 merge of '4f47546a7fcac5e20d0d9ac04bcae904bb155cc9'
and '71ed1d74f02291ae56a495e97fae65970bfbdd30'
2012-04-20 13:55:39 +00:00
zzz
112b88a7f9 * Fix i2psnark dir when started from Windows no-wrapper (ticket #627) 2012-04-20 13:44:41 +00:00
kytv
c61b73c281 use <os family="unix"> instead of just <os = 'unix'> 2012-04-20 13:26:23 +00:00
zzz
79a7c14fdf remove search box 2012-04-20 13:25:29 +00:00
kytv
e4513d18b9 manpage updates 2012-04-19 23:25:32 +00:00
kytv
7870ededcb Updated en locale files pushed to tx 2012-04-19 23:24:20 +00:00
kytv
195a4e971d merge of '06de0d416fefcfbd6ce12716ce5fed4eefe8a711'
and 'e78c33c88a31edac9e53dd6cdf973886ecabd996'
2012-04-18 18:48:26 +00:00
kytv
aa02358b1b disapproval of revision '78927d1f7087f93dca9a96ac375d05d01596fb74' 2012-04-18 18:48:20 +00:00
kytv
18fe05b9ef merge of '06b8a711c60dbb6a9d628c4c5ffd8b205176271a'
and 'c1edfeadb75181e65ad8d4c0005b861f3563dd5b'
2012-04-18 18:47:53 +00:00
kytv
5b5b3b203c s/unix|mac/unix/ 2012-04-18 18:47:43 +00:00
kytv
49cee5bf58 disable the 'convenience links' in /etc/i2p. 2012-04-18 01:45:08 +00:00
kytv
ac1b51c9ac Fix installer-windows build target
Izpack tries to parse the 'unix-only' files in Windows. If we don't copy them,
the installation will fail in Windows. Therefore, moving the files that were in
the preppkg-unix target to the preppkg-base target. They're so small I don't
see how this will be a problem.
2012-04-18 01:44:17 +00:00
kytv
746b91f257 Since it was suggested, I'm adding my eepsite 2012-04-18 01:41:38 +00:00
kytv
77d970fd5a debian: initscript: reorder, change some exit statuses 2012-04-17 12:33:30 +00:00
kytv
678c87d0f4 bump version to -27 (debian package fix and people can get the new wrapper & geoip) 2012-04-17 11:49:45 +00:00
kytv
f352a38836 revert back to linking to glassfish-javaee.jar (fixes susidns and i2pbote in Debian) 2012-04-15 22:19:44 +00:00
kytv
d402f0c93d history update 2012-04-14 17:46:17 +00:00
kytv
7093a57a03 update GeoIP using Maxmind's April 2012 db 2012-04-14 17:44:30 +00:00
kytv
6a9432d62e Update the Tanuki Java wrapper to v3.5.14
All are from the "delta-pack" with the following exceptions:

* binaries for FreeBSD have been compiled in FreeBSD 7.4 to eliminate the
  dependency on FBSD v6 compatibility libs. They've also been stripped.
* Tanuki doesn't offer win64 binaries. Since the x64 binaries had to be
  compiled anyway, I've added an itoopie icon to the binary and both x86 and
  x64 binaries are compiled by me.
* Linux PPC binaries have been compiled by me since upstream mistakenly ships a
  64bit PPC binary as a 32bit binary.
* Linux ARMv5 have been compiled by me.
* The Linux x64 and x86 binaries have been stripped.
2012-04-14 17:38:08 +00:00
kytv
7440e64eb6 dropping FAT osx wrapper before adding new 'non-FAT' one 2012-04-14 17:25:49 +00:00
zzz
97436e8357 Wrapper files for armv7.
Compiled on trimslice:
    gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) 
    java version "1.6.0_18"
    OpenJDK Runtime Environment (IcedTea6 1.8.13) (6b18-1.8.13-0ubuntu1~11.04.1)
    OpenJDK Zero VM (build 14.0-b16, mixed mode)
    Wrapper 3.5.14 GPLv2
    All binaries stripped.
2012-04-14 14:16:36 +00:00
kytv
f9ff90eb72 update comments 2012-04-12 21:05:19 +00:00
kytv
6acece85a2 German, Spanish, and Swedish translation updates from Transifex 2012-04-12 20:25:52 +00:00
zzz
2d24f01831 - Non-default theme cleanups
- Theme and translate home page logo
2012-04-12 17:54:44 +00:00
zzz
f2b228561f strip DOS line endings to make diffing to other themese easier 2012-04-12 15:29:26 +00:00
zzz
ce9cae4ff8 fix whitespace issues 2012-04-12 15:21:21 +00:00
zzz
c3a387d646 Try again to fix console on Windows w/o IPv6 by starting connectors individually 2012-04-12 14:54:50 +00:00
zzz
b24085bbe5 prevent very early NPE 2012-04-12 14:48:18 +00:00
kytv
41419738c5 add keys.i2p 2012-04-09 15:27:07 +00:00
kytv
dd65f174ef Debian: Explicitly create the home directory in the postinst
Older versions of adduser create it automatically. The version in Debian unstable apparently does not...
2012-04-08 20:35:30 +00:00
kytv
d888d4834d Debian: update symlinks 2012-04-03 21:17:14 +00:00
str4d
ce8cd91d72 propagate from branch 'i2p.i2p' (head 3002b47d5d20180f84fb6a4f161823bc751989be)
to branch 'i2p.i2p.unittests' (head 97dc8de19916c3d0c7ec42790800c1e23f9ce9e8)
2012-03-30 05:10:53 +00:00
str4d
0cefaba925 More excess whitespace removed 2012-03-30 04:40:56 +00:00
zzz
565807126c * RouterInfo: Fix fatal NPE in last checkin 2012-03-28 19:17:39 +00:00
zzz
bed548d5af 24 2012-03-27 20:34:40 +00:00
zzz
fbd230f21e * RouterInfo: Add method to validate sig during read-in for speed 2012-03-27 20:25:26 +00:00
zzz
dc402acd4a * FloodfillVerify:
- Fix verifies stuck on one peer by blamimg the verify peer on failure
    - Follow DSRM in response to RI verifies, to help integration
    - Increase floodfill verify timeout
2012-03-27 20:10:30 +00:00
zzz
e3dab56e79 Delay router down message until two consecutive fails 2012-03-27 20:08:11 +00:00
zzz
d3578e2a2e graphs CSS tweak 2012-03-27 20:07:30 +00:00
zzz
7a6e7baf18 generics and final 2012-03-27 20:07:12 +00:00
sponge
97f23286d3 allow SHOUTcast/icecast to work over the http proxy + cleanups 2012-03-27 17:41:02 +00:00
zzz
11ff89fef2 - Try again to fix console on Windows w/o IPv6 (ticket # 621) 2012-03-26 14:07:38 +00:00
zzz
764a7f2e13 remove unused private items (eclipse) 2012-03-26 00:52:06 +00:00
zzz
1db58dee89 remove unused local variables (eclipse) 2012-03-25 22:16:03 +00:00
zzz
f13956d380 remove unused imports (eclipse) 2012-03-25 21:45:18 +00:00
zzz
522ae4eb41 fix fallthrough 2012-03-25 20:52:57 +00:00
zzz
3e889d2747 remove unnecessary casts (eclipse) 2012-03-25 20:42:41 +00:00
zzz
ed13424913 - Move oldconsole rendering from Router to OldConsoleHelper 2012-03-24 23:04:05 +00:00
zzz
bdfca07626 - Fix dup torrent msg with magnets (tickets #433 and #504)
- Fix state when storage dies during transition out of magnet mode
    - Fix NPE in magnet mode
    - Error logging improvements
    - Support add-torrent with infohash alone
    - CSS tweaks
2012-03-24 12:58:13 +00:00
str4d
ba3bc9e2ed Uncommented two Datagram tests that currently throw NullPointerExceptions 2012-03-24 11:18:37 +00:00
str4d
f164951848 Actually test something in DatagramTest.testBadagram, remove excess whitespace 2012-03-24 08:04:49 +00:00
str4d
bfaf72a547 Added a couple of tests for net.i2p.client.naming 2012-03-24 05:09:31 +00:00
zzz
008c79e743 comment out unused GarlicConfig methods 2012-03-23 17:02:32 +00:00
zzz
0d565818d4 final 2012-03-23 17:01:34 +00:00
zzz
c1a7f90860 test cleanup 2012-03-23 17:01:24 +00:00
zzz
c2e36453b8 undeprecate for syndie 2012-03-23 17:00:51 +00:00
zzz
675e8a91a4 * RetransmissionTimer: Instantiate per-destination 2012-03-22 20:40:35 +00:00
zzz
cae94320b5 remove FlushTimer 2012-03-22 19:55:40 +00:00
zzz
bafef846d9 * SimpleScheduler, SimpleTimer, SimpleTimer2: Replace static instances
with I2PAppContext-rooted references
2012-03-22 19:53:05 +00:00
zzz
db42a46c71 home page CSS 2012-03-22 19:49:48 +00:00
zzz
adcd1e8d9a * Reseeder: Get rid of static instance, root in netDB,
don't use system properties for status
2012-03-22 19:47:44 +00:00
zzz
ca57b71266 * Router: When removing a config setting, remove from context also 2012-03-22 19:40:17 +00:00
zzz
e3da181cea * NetDB:
- Don't reread RI if netdb date is recent
    - Prevent LS/RI overwrites
    - Disallow hash mismatches in RI files
    - Reseed won't fetch our own RI
    - Reseed won't overwrite recent RIs
2012-03-20 18:38:28 +00:00
zzz
3da6ccfbbe make runRouter() public 2012-03-20 14:52:22 +00:00
zzz
444ba47463 * i2psnark: Message area tweaks and clear link 2012-03-20 14:09:17 +00:00
str4d
377aa9bca1 In core build.xml, tell junit to look for the hamcrest libraries
hamcrest-core.jar, hamcrest-library.jar and hamcrest-integration.jar should be
present in $ANT_HOME/lib/ (real or symlinked).
2012-03-20 00:29:14 +00:00
sponge
4ffbfce51e Plugins: Order and reverse order plugin names for start/stop all cases. 2012-03-19 12:37:39 +00:00
sponge
d1ed30e79c Plugins: less confusing message, fix CNFE by catch and ignore on delete. 2012-03-19 01:46:47 +00:00
zzz
8ca5591933 fix check aliases override 2012-03-18 14:05:14 +00:00
zzz
7d9db79619 fix build 2012-03-18 00:07:46 +00:00
zzz
508533b83e -17 2012-03-17 22:07:51 +00:00
zzz
0a521b7456 * BuildHandler: Implement restart and shutdown to stop the thread 2012-03-17 21:58:41 +00:00
zzz
0c348ec17e * FileUtil: Better logging of weird unpack200 errors 2012-03-17 21:56:20 +00:00
zzz
df8bab6b72 * Streaming: Scheduler cleanup 2012-03-17 21:55:05 +00:00
zzz
f6fb4b4be3 news header 2012-03-17 21:53:14 +00:00
zzz
0f74ccd446 add servlet version 2012-03-17 21:52:48 +00:00
zzz
02bde80725 * Jetty: Don't extract wars 2012-03-17 21:52:17 +00:00
zzz
e2a39a3eb5 * I2PTunnel: Make CLI-only methods private, and static where possible 2012-03-17 21:49:11 +00:00
zzz
3a2fe5e860 * OCMOSJ: Refactor cache to its own class, make non-static 2012-03-16 12:20:29 +00:00
zzz
fb8244ee1a javadoc 2012-03-16 12:18:04 +00:00
zzz
045627a583 throw ISE on attempt to change peer value 2012-03-16 12:17:07 +00:00
zzz
e7898b5b8f * FragmentHandler: Zero-copy read of unfragmented messages
for speed and to reduce object churn
  * FragmentedMessage cleanup
2012-03-16 12:16:05 +00:00
zzz
080f435708 * TransportManager: Fix fatal exception on soft restart caused by DHSKB refactoring 2012-03-16 12:13:20 +00:00
zzz
f2a3d597dd * Jetty: Add I2P mime types to default eepsite config 2012-03-16 12:11:31 +00:00
zzz
74743357d0 * TrustedUpdate: Preserve default key names even when keys are set
in advanced config
2012-03-16 12:09:49 +00:00
zzz
1de88909e9 * Home page: Tag tooltip; CSS tweaks; news tweak 2012-03-16 12:08:43 +00:00
zzz
f7dc55f087 * HTTP Proxy: Jump and addresshelper page tweaks 2012-03-16 12:07:13 +00:00
str4d
67da35ab35 Commented out test for net.i2p.data.Lease.getNumSuccess() / getNumFailure 2012-03-16 05:08:31 +00:00
str4d
136d77a8aa Fix YKGenerator test - methods no longer static 2012-03-16 04:51:55 +00:00
str4d
bf0b59b3b3 Remove DHSessionKeyBuilderTest from CryptoTestSuite 2012-03-16 03:18:53 +00:00
str4d
f19bc6a4b0 Moved DHSessionKeyBuilderTest to net.i2p.router.transport.crypto 2012-03-16 03:08:10 +00:00
str4d
79ab065500 propagate from branch 'i2p.i2p' (head e1c79060790ae24b2a96aff2857477d6528ae7c6)
to branch 'i2p.i2p.unittests' (head 357abd51672dd9950cbac6dd30ded117fe5695e0)
2012-03-16 02:30:42 +00:00
str4d
9d07bc241c Replace hostname included by junit in reports with "i2ptester"
The fake hostname can be overridden by setting the host.fakename property.
2012-03-16 01:41:23 +00:00
kytv
d9ba62aa2c Update paths, add new files 2012-03-15 14:51:34 +00:00
sponge
1f407bc34f Plugins 2012-03-15 00:39:11 +00:00
zzz
1aa6367517 orb->org 2012-03-14 12:45:27 +00:00
zzz
2436d86000 * DHSessionKeyBuilder:
- Move from core to router/transport
    - Make non-static, instantiate in TransportManager
    - Generate keypair in constructor and make final
      to move more processing to the precalc thread
      and eliminate races
    - Synchronize getSessionKey() to eliminate races
    - Comment out unused methods
  * UDPTransport:
    - Make key builder final in InboundEstablishState to
      eliminate rare NPE (ticket #406)
    - Remove unused static instance
2012-03-14 12:09:02 +00:00
zzz
17f9280b3f * Jetty:
- Set default cache-control for webapps and eepsite
    - Disable dir listing for console webapps
  * WebAppStarter: Remove static log
2012-03-14 12:04:20 +00:00
zzz
326b9998fd make YKGenerator non-static; control from ElGamalEngine 2012-03-14 11:59:24 +00:00
zzz
3b64ce7408 remove static logs 2012-03-14 11:57:06 +00:00
zzz
7c88180b83 remove static logs 2012-03-14 11:55:13 +00:00
kytv
7d0741bd7e Add plugin site 2012-03-13 21:48:02 +00:00
kytv
65612a1c86 merge of '7bb8bf1ecf9084d263f4d9a764330dd19faf6102'
and 'bd10ddbf34b82a92bfbca38cefbba707a709c251'
2012-03-13 21:38:56 +00:00
kytv
a408a43d96 Add plugin site host key 2012-03-13 21:38:25 +00:00
sponge
bc0a38b405 Fix grammar error, thanx user 2012-03-13 19:54:07 +00:00
sponge
913994f312 Add sponge.i2p :-D bump version. 2012-03-13 11:11:41 +00:00
sponge
0fabbc9039 Plugins: bugfix and defer update. 2012-03-13 09:49:15 +00:00
sponge
92c3d33ce5 Plugins: Handle 'file://' URLs for installation and updates. 2012-03-13 05:49:02 +00:00
zzz
d29da5597f merge of '4db3befef542b29ac21bba7ed51b609b6e9223ea'
and 'fe5447c647ccadee0d67aa5db36f5ed785520a1b'
2012-03-12 15:02:49 +00:00
zzz
2415091a2f * Console:
- Better IPv6 test, hopefully will work on Windows
    - Hide home page flags once language is selected
    - Home page shrinkage and other CSS tweaks
2012-03-12 14:30:38 +00:00
sponge
05537ba1b2 Slackware package script updates 2012-03-11 23:54:02 +00:00
zzz
703f28e87d * Build:
- Include old commons logging classes in commons-logging.jar
    - Preserve manifests in Jetty/Tomcat jars
  * Jetty Logger: Promote warns to erros when a Throwable is the second arg
2012-03-11 18:30:43 +00:00
sponge
f91f83faef fix broken comment in jetty.xml 2012-03-11 16:46:45 +00:00
kytv
d598396bb2 Add 'unsignedbuild' id 2012-03-11 13:02:51 +00:00
zzz
fdb1f9dd39 IPv4 check 2012-03-10 22:07:15 +00:00
zzz
9e3b49d67f -10 2012-03-10 21:59:26 +00:00
zzz
f6bda355b9 * Build: Add new jetty jars to router.jar classpath so it works
on very old installs with individual jars specified in the
    wrapper.config classpath
2012-03-10 21:55:45 +00:00
zzz
a34b674f7d more comment updates 2012-03-10 21:54:55 +00:00
zzz
307826c4d3 move the update-all button 2012-03-10 21:54:38 +00:00
zzz
9faba9fd30 * Console: Test if IPv6 addresses will work before instantiating
connectors, so Jetty will still start without them
2012-03-10 21:53:29 +00:00
zzz
87c04bf00b * configloggging: Fix clearing log overrides 2012-03-10 21:51:50 +00:00
zzz
7bd83f83ed * Jetty Logger: Put a note in wrapper log saying where the logs went 2012-03-10 21:51:20 +00:00
zzz
528ef4dd1a * HTTP Proxy: Fix generation of jump links (ticket #616),
broken by refactoring in -1
2012-03-10 21:50:45 +00:00
zzz
5ab17da73d * Simplify default eepsite base and CGI contexts to use a Context
instead of a ContextHolder, ServletHandler, and ServletHolder.
    This also fixes / which returned a zero-length file,
    broken in the last checkin.
2012-03-09 20:00:18 +00:00
echelon
0c55af2622 new i2p-projekt.de reseed SSL certificate. Sorry. 2012-03-09 16:52:55 +00:00
zzz
e331800898 * Update default eepsite base context to use DefaultServlet
instead of ResourceHandler, to provide resume, directory
    indexes, caching, etc.
2012-03-09 16:03:27 +00:00
kytv
e4257f28c9 Add note about 32bit libs 2012-03-09 02:00:07 +00:00
zzz
97f402be0b * SessionKeyManager:
- Don't use unacked tagsets after consecutive ack failures
      and revert to full ElGamal if necessary (ticket #574)
    - Synchronize creation of new sessions to prevent dups
    - Don't remove an unacked session until it's really out of tags
    - Failsafe removal of old unacked tagsets
    - Cleanups, final, comments, log tweaks, debug.jsp tweaks, synchronization tweaks
2012-03-08 17:48:19 +00:00
zzz
1e978ea435 javadoc 2012-03-08 17:46:56 +00:00
zzz
629c7862ca log tweak 2012-03-08 17:46:15 +00:00
zzz
7006ffb75d remove calls re-setting defaults 2012-03-08 17:45:29 +00:00
zzz
b42993b495 * GarlicConfig: Remove unused reply block methods 2012-03-08 17:44:41 +00:00
kytv
a9935cb609 Spanish and German translation updates from TX.
Updated EN po files to push to TX.
2012-03-07 01:39:39 +00:00
kytv
05be39d286 minor updates 2012-03-06 19:25:19 +00:00
kytv
0c77f7a82d update comments to reflect that we're now using jetty6 2012-03-06 19:25:03 +00:00
kytv
18f113d8e7 add pkg200 target, fix dist200 target 2012-03-06 19:23:28 +00:00
zzz
175e464c17 merge of '6719c390f50bba07ed4913fa1578249050506422'
and 'd766ba05d9b2db6d6f7c0ea14b5ad0252c274c2d'
2012-03-06 14:16:04 +00:00
zzz
0cea3e03ae * Webapp class loader: Fix dup classes in classpath
caused by last checkin (symptom: i2psnark in wrong directory)
2012-03-06 14:04:04 +00:00
zzz
de2b204646 * viewstat.jsp: Properly close the ImageOutputStream to fix
NPEs in the finalizer, probably was the root cause of
    what we blamed on Jetty
2012-03-06 14:02:12 +00:00
zzz
e1c3979af7 * Jetty logger: Fix stack trace logging 2012-03-06 14:01:13 +00:00
zzz
46438b7412 * i2psnark: Fix NPE on magnet link addition 2012-03-06 13:59:32 +00:00
kytv
6a103a1492 minor changes to some targets/descriptions 2012-03-05 23:58:56 +00:00
kytv
a24937b7fd improve display of dark, classic, and midnight on the new homepage and center the search box under the news 2012-03-05 23:57:51 +00:00
zzz
d7c1e9724b merge of 'c09b40fe67ffc403c484ac4b14d896de48d37d9c'
and 'c269d35a60d164027bb1d1fbb6d30c06ffd2292d'
2012-03-05 15:24:21 +00:00
kytv
224405d737 Allow EXEs to be built on AMD64
Enabling this should be safe since we will ship separate installers for
Win/non-Win. Those that don't want to build the EXEs can set noEXE in build.properties,
Even better might be to run one of
* ant installer-freebsd
* ant installer-linux
* ant installer-nowindows
* ant installer-osx
2012-03-05 15:07:04 +00:00
zzz
6c2d4ded1c add time interval to graph legends 2012-03-05 15:00:52 +00:00
zzz
ee22244b53 merge of '166d63ea25334cf53075e0d418ececcb1d8bc6ca'
and 'e42352d45c2c9304562eed404c9c2dd8120becc5'
2012-03-05 15:00:02 +00:00
kytv
5376858175 Add WithJavadoc targets that also include Jetty 2012-03-05 13:39:54 +00:00
kytv
910f60031a html fix 2012-03-05 01:46:41 +00:00
zzz
3240dacfe8 remove dup utility jar building, build win and non-win installers for release 2012-03-05 00:52:21 +00:00
zzz
76c0f56be8 * Plugins: Fix setting webapp classpath on Jetty 6 2012-03-05 00:41:36 +00:00
zzz
d85ae48f4e specify action so that the user will go to the top of the page to see the result even if an anchor was specified 2012-03-05 00:40:41 +00:00
zzz
e99b2064e7 log tweaks 2012-03-05 00:37:48 +00:00
zzz
57f4ede102 increase floodfills to 250 2012-03-05 00:37:20 +00:00
zzz
0c55de7fcc * viewstat.jsp: Send Connection: Close to work around Jetty bug
http://jira.codehaus.org/browse/JETTY-1346
2012-03-05 00:36:54 +00:00
kytv
af1a49e5f4 s|update\.killyourtv\.i2p/javadoc|i2p-javadocs.i2p| for homepage
..and add to hosts.txt
2012-03-04 23:20:26 +00:00
kytv
28e3ab9132 Minor tweaks so that debs can be built again
Work is needed so that I2P is built using jetty packages from
Debian/Ubuntu.
2012-03-04 18:40:01 +00:00
zzz
60f35bdd5d history for prop, -4 2012-03-04 17:01:17 +00:00
zzz
44db814ded remove old jetty 5 classes in case you forgot to distclean after updating 2012-03-04 14:28:50 +00:00
zzz
349a01265f backwhacks 2012-03-04 04:30:16 +00:00
zzz
a0a9c23bcd fixups after prop 2012-03-04 02:48:47 +00:00
zzz
2b81cee653 propagate from branch 'i2p.i2p.zzz.jetty6' (head b2ad0d72311d5ec26270cfcbbc79d128b268869b)
to branch 'i2p.i2p' (head b05b73d4740740f306a665e4b354d412eab2f328)
2012-03-04 00:34:00 +00:00
zzz
140ffc5c5e - /confighome validation fixes
- AJAX fixes
  - Translate 'router is down' message
2012-03-03 22:55:24 +00:00
zzz
8cd9fb80ba history for prop, -2 2012-03-03 20:25:49 +00:00
zzz
21ce36db9c merge of '20d8216d0354a2fa3dbd14fa595ebe0ee080a9d8'
and 'b97f3cabaa528502fd5728f44345cc09348b74a6'
2012-03-03 20:20:30 +00:00
zzz
f010b27b14 Home page:
- Convert ajax to use shared script
  - CSS tweaks
  - Add missing icons
    Silk icons: See licenses/LICENSE-SilkIcons.txt
2012-03-03 20:17:02 +00:00
zzz
b0a682f606 propagate from branch 'i2p.i2p.zzz.homepage' (head 27c8ea684056ce34ea81acdfd18571776ca63641)
to branch 'i2p.i2p' (head 83f37b19742045fa42ed71a0abd8e90d080c2c05)
2012-03-03 19:05:15 +00:00
zzz
e2acc9fdd2 * i2psnark:
- CSS tweaks
    - Ajax fixes
    - Move js to console in prep for merging w/ homepage
2012-03-03 18:58:31 +00:00
zzz
0e8d3d1862 remove bw stats from netdb effective next release 2012-03-03 18:21:00 +00:00
zzz
a0f714097a css tweak 2012-03-03 18:20:06 +00:00
zzz
15e182809d html fix 2012-03-03 18:19:50 +00:00
kytv
7673d2ba04 Susimail: HTML fixes 2012-03-03 18:10:45 +00:00
kytv
7a765757dd Proxy pages: HTML validation fixes for the proxy pages 2012-03-03 16:31:05 +00:00
kytv
2db086ee32 Add Updater200WithJetty target 2012-03-03 13:46:54 +00:00
kytv
366d79ddad Adding missing HTML tags 2012-03-03 01:00:31 +00:00
kytv
2bff0d6bcc HTML validation fixes 2012-03-02 22:32:45 +00:00
kytv
1aa24a38a4 Various HTML fixes 2012-03-02 18:46:34 +00:00
zzz
f62c3047b5 history for prop, -1 2012-03-02 01:34:21 +00:00
zzz
0cdff150f5 propagate from branch 'i2p.i2p.zzz.test' (head 44ecb300f6f5655b9b8699049d2fba046822deed)
to branch 'i2p.i2p' (head 5120d6c371d7cba9f201b48a142b0e0ead028cdd)
2012-03-02 00:18:54 +00:00
zzz
75eda7e1b1 log tweak 2012-03-01 23:52:56 +00:00
zzz
f22ac28e4d search param encoding 2012-03-01 23:46:06 +00:00
zzz
33964fac45 Fixes for:
IPv6 addresses
    Reject all hostnames w/o dots except IPv6
    http://i2p/b64dest
Log tweaks
Add nicer ahelper-notfound error page
2012-03-01 23:38:22 +00:00
kytv
5e5e4f6f2c HTML fix 2012-03-01 19:16:44 +00:00
kytv
4a74bd0fe7 HTML fixes 2012-03-01 19:02:32 +00:00
zzz
e7bcff5e71 - Refactoring to use Jave URI parser to better handle
escapes, IPv6 addresses, ports
    - Rewrite i2paddresshelper scanning/removal

intermediate checkin, bug fixes to follow
2012-03-01 18:39:07 +00:00
zzz
cadedeb06c * Build: Add built-by to jars; check for corrupt jars on debug page 2012-03-01 16:04:17 +00:00
zzz
5af6c97bee log tweaks, final 2012-03-01 14:21:54 +00:00
zzz
cf41068fef SDK message 2012-03-01 13:41:24 +00:00
str4d
81bd0fcbf4 propagate from branch 'i2p.i2p.str4d.i2ptunnel' (head 237102a8f647caf98bf0491af5de6f636e254722)
to branch 'i2p.i2p' (head 3d9f6d9555224cc3277ca10fd9409c83422758eb)
2012-03-01 05:07:47 +00:00
str4d
b6f7321497 Fix the UTF8 POSTing issue 2012-03-01 05:03:29 +00:00
zzz
538427c269 - Synchronize StoreJob.sendNext() to avoid dups
- StoreState finals
2012-02-29 18:49:49 +00:00
zzz
f61183d2d8 * DataStructures:
- Remove static logs
    - Sort addresses in RouterInfo at initialization only;
      change from Set to List to save space
    - Remove unused counters in Lease to save space
    - Increase max leases to 16
2012-02-29 18:09:16 +00:00
zzz
48551f0617 NetDB: Reenable RI store verifies. Was disabled in 0.7.9;
checkin comments claim it was reenabled in 0.7.10
but it didn't actually happen, probably due to bad merge.
2012-02-29 17:50:54 +00:00
zzz
6f682c1e71 change console link 2012-02-29 15:30:28 +00:00
zzz
f747febd0a home page updates 2012-02-29 15:29:29 +00:00
zzz
1f9ab5d880 propagate from branch 'i2p.i2p' (head 3d9f6d9555224cc3277ca10fd9409c83422758eb)
to branch 'i2p.i2p.zzz.homepage' (head 0657f1e52c859e06b78e55fe04656567bfba3bf0)
2012-02-29 15:27:37 +00:00
zzz
f43b0be5b8 Check in the 840 KB of jars we need from Jetty 6.1.26
(Apache 2.0 license) instead of downloading a 25 MB zip
2012-02-29 15:12:25 +00:00
zzz
bb46535e71 propagate from branch 'i2p.i2p' (head 3d9f6d9555224cc3277ca10fd9409c83422758eb)
to branch 'i2p.i2p.zzz.jetty6' (head 0212d710e5a4eb30249201015f045d43f44650cb)
2012-02-29 14:37:02 +00:00
zzz
2bc70b53c1 debug log 2012-02-29 13:45:02 +00:00
str4d
786a261a70 Fixed usage of assertEquals - should be assertEquals(expected, got) 2012-02-29 05:34:13 +00:00
str4d
a226d25dc6 Test getters etc. in RateStat 2012-02-29 05:01:21 +00:00
zzz
ede1b1954c remove static logs 2012-02-28 15:58:02 +00:00
zzz
17f7264863 remove unused counters and methods 2012-02-28 15:26:31 +00:00
zzz
d6d8c0d119 remove static logs 2012-02-28 14:50:39 +00:00
zzz
4f6ed70044 remove static logs 2012-02-28 14:35:32 +00:00
zzz
cf5d7d2f08 remove dtg from updater 2012-02-28 13:28:25 +00:00
zzz
d0dca206f7 release script tweaks 2012-02-28 13:20:34 +00:00
kytv
382dd3405a merge of '19c723e9710a494c2745c7a6e9476faf11f19fe1'
and '9f02425e8331315552436375df61b3dd03e6ef56'
2012-02-27 23:16:51 +00:00
kytv
a655a7848b debian: changelog update, policy update 2012-02-27 22:53:10 +00:00
kytv
9ac0a91f17 html fix (selected=true isn't valid) 2012-02-27 21:31:17 +00:00
kytv
49d7dace3b s/mbuild/build/
mbuild_jbigi.sh was into build_jbigi.sh
2012-02-27 21:25:40 +00:00
zzz
bda3fbbe63 add icon to installer exe 2012-02-27 21:15:56 +00:00
kytv
e2e578a66d merge of '228c3961aed59e47a5cbc291817fc7c41ffeb54e'
and '55bddb9107328a5d5a3fd697e0599dda7d3ff2e3'
2012-02-27 19:06:21 +00:00
str4d
d436c846ac Temporarily exclude slow core tests for dev purposes 2012-02-27 03:29:13 +00:00
str4d
24268c5130 Exclude classes from code coverage report that aren't in net.i2p.*
The classes are specifically excluded rather than only including net.i2p.*
so that only classes we know we want to exclude get excluded.
2012-02-27 03:26:58 +00:00
zzz
6ebd1f121a installer build fixups 2012-02-26 23:05:21 +00:00
zzz
394943c36f debug output of LS encryption key to correlate with SKM debug page 2012-02-26 21:15:31 +00:00
zzz
6ee9b79e45 generics, final 2012-02-26 21:13:06 +00:00
zzz
da482c373e new single graph page 2012-02-26 17:34:22 +00:00
str4d
22900a0d91 Fixed RouterAddressTest.testToString to actually test the returned String 2012-02-26 09:30:27 +00:00
str4d
e7922c4ded Added some tests of setOptions to RouterAddressTest 2012-02-26 04:57:31 +00:00
str4d
f19ef3e486 Fix test that would always pass 2012-02-26 03:01:48 +00:00
str4d
5b6a23b13a propagate from branch 'i2p.i2p.str4d.i2ptunnel' (head 382a93d72f9ae55f3e251a6f3cbf6e35df2e560d)
to branch 'i2p.i2p' (head 36eae7cbb8817fb68bb042e8207c6c955264f393)
2012-02-25 21:14:34 +00:00
str4d
ce1e055848 Removed WizardBean - it does nothing extra over EditBean 2012-02-25 19:37:54 +00:00
str4d
f72e16f571 Close line break tags properly 2012-02-25 19:28:22 +00:00
zzz
fc3343270a fix LS count 2012-02-25 18:40:27 +00:00
zzz
e1c9402d3f propagate from branch 'i2p.i2p' (head 36eae7cbb8817fb68bb042e8207c6c955264f393)
to branch 'i2p.i2p.zzz.test' (head 33f78a361bfef38b120fdf55d9e9535f3be96d6e)
2012-02-25 17:49:09 +00:00
str4d
4148aa54f3 Need to run clean and prepareTest before test in router build.xml 2012-02-25 01:48:31 +00:00
str4d
204440b06b Run full test reports with fulltest target, not just junit report 2012-02-25 01:46:46 +00:00
str4d
6a26c0b621 Edited router build.xml to match core build.xml (inc. clover, cobertura stuff) 2012-02-25 01:43:15 +00:00
str4d
c955adf7f6 Set up report targets properly in main build.xml 2012-02-25 01:29:08 +00:00
str4d
c68d53faf3 Removed fullclovertest target from main build.xml
Clover usage is triggered by setting with.clover instead.
2012-02-25 01:23:17 +00:00
str4d
ceda7c9ca0 Fix jbigi.jar path in test target of router build.xml 2012-02-25 01:21:31 +00:00
zzz
54f0cae2ff refactor proxy.i2p server to its own class 2012-02-24 17:58:54 +00:00
zzz
eeb9ee0852 snark conn limits 2012-02-23 19:31:25 +00:00
zzz
87da4b78ab add negative cache to BFNS 2012-02-23 19:06:21 +00:00
zzz
141ad67650 ajaxify the refresh 2012-02-23 17:41:06 +00:00
zzz
a288fc52e0 Move icon URL from _icons to .icons 2012-02-23 15:40:31 +00:00
zzz
667bd46643 hide stat log config unless already enabled 2012-02-22 15:41:04 +00:00
str4d
849c407712 Added clover targets to core build.xml as well, so either will work
Pass in the absolute location of clover.jar as the with.clover property
to activate the clover targets.
2012-02-21 04:05:27 +00:00
zzz
3131e65b66 fix redirection; change header 2012-02-20 14:32:48 +00:00
str4d
a2217b2b36 Fiddle with cobertura definitions a bit in core build.xml
To run with cobertura, execute the following in "core/java/":
ant -Dwith.cobertura=/usr/share/java/cobertura.jar cobertura.report
2012-02-20 03:44:23 +00:00
zzz
13731e7b35 add b64 hash 2012-02-19 20:57:44 +00:00
zzz
3fbd8b8d14 - Fix custom tracker list
- Add tracker config form
- Remove custom tracker from create form
- More icons in buttons
2012-02-19 19:52:16 +00:00
zzz
3876f74f6c tooltip 2012-02-18 19:19:42 +00:00
zzz
b47aa34d6a add private option in UI 2012-02-18 18:50:57 +00:00
zzz
295242316b Disable PEX/metadata extensions and open trackers for private torrents
Handle announce URLs with parameters correctly
2012-02-18 17:58:54 +00:00
zzz
274e37b284 propagate from branch 'i2p.i2p' (head 0a3db5b65f8fdc3e91000c9dff9e679401b52f72)
to branch 'i2p.i2p.zzz.jetty6' (head da78bc5726f3715ec8083aa86bcaa6c05896b8d6)
2012-02-18 15:28:34 +00:00
zzz
1997be371c propagate from branch 'i2p.i2p' (head 0a3db5b65f8fdc3e91000c9dff9e679401b52f72)
to branch 'i2p.i2p.zzz.homepage' (head 73d71bde13883d204e50f497efe264d8643fb8fa)
2012-02-18 15:28:19 +00:00
zzz
c957577e72 propagate from branch 'i2p.i2p' (head 0a3db5b65f8fdc3e91000c9dff9e679401b52f72)
to branch 'i2p.i2p.zzz.test' (head 8648a7d67ffff19124cafdd14648c13dedccd2ba)
2012-02-18 15:23:24 +00:00
zzz
cf463100cd stub out private mode 2012-02-18 15:22:40 +00:00
str4d
c7d473a7eb Shuffle round mkdirs and deletes in router build.xml to match core build.xml
batchtest has a todir config option that makes manual copying unnecessary.
2012-02-18 02:13:46 +00:00
str4d
d1a03f500f Moved mkdir above delete in core build.xml and removed mkdir from base build.xml
mkdir does nothing if the directory exists, whereas delete fails by default
if the directory doesn't exist. Also, mkdir creates parent dirs as needed.
2012-02-16 02:58:25 +00:00
str4d
8a32aad6c3 Shuffled build targets around to group together ones related to unit tests 2012-02-16 00:08:27 +00:00
zzz
45ba9e1bd4 fixup after prop 2012-02-04 15:45:03 +00:00
zzz
6107e38e56 propagate from branch 'i2p.i2p' (head 0f4af64e64536c467b623286bce659dd2dfe9342)
to branch 'i2p.i2p.zzz.jetty6' (head d525108d8e9ecb842a99bb81c1138c43b5e39653)
2012-02-04 15:42:23 +00:00
zzz
3af2577c11 propagate from branch 'i2p.i2p' (head 0f4af64e64536c467b623286bce659dd2dfe9342)
to branch 'i2p.i2p.zzz.homepage' (head dde6a3d7db54894a2ac30a2af6cbb04cbb92296a)
2012-02-04 15:40:22 +00:00
zzz
f7dee01609 fix form default on chrome 2012-01-25 16:40:55 +00:00
zzz
6e44710b94 - escape html for adds and queries
- change config separator char
- fix enter in add boxes
- fix alt and title tags
2012-01-25 16:22:04 +00:00
zzz
0d494c50af add firewall and reseed status on /home 2012-01-25 15:01:19 +00:00
zzz
00b8e14adf /confighome:
- config search engines
- add icons
- restore defaults button
2012-01-25 14:34:54 +00:00
zzz
61290dfbcf * Old console to /console, new redirect script at /index 2012-01-25 02:50:42 +00:00
zzz
fbca6ac1fd * New home page, including basic AJAX, home page config and search 2012-01-25 02:38:49 +00:00
zzz
061f96ad89 Use ${ant.home}/lib/ant.jar instead of pulling ant.jar from Jetty 2012-01-23 16:44:08 +00:00
zzz
221499c1a8 propagate from branch 'i2p.i2p' (head 156f8e6137be3c25aa70176fe0a78218b898a684)
to branch 'i2p.i2p.zzz.jetty6' (head 960f416b20e26662b1b5b30468a85dbb25f09ffd)
2012-01-22 18:30:41 +00:00
zzz
ba01451038 propagate from branch 'i2p.i2p' (head 7e9829897ed454bcb4a8e64b029060f7e90cbbfa)
to branch 'i2p.i2p.zzz.jetty6' (head b9984717e63b03b3b5fcf3a9729d55411aa65e89)
2012-01-18 19:16:53 +00:00
zzz
6198739f7a propagate from branch 'i2p.i2p' (head 899a1923586f3d7d622bd02e03c87717566617c4)
to branch 'i2p.i2p.zzz.jetty6' (head cb3e33be282b6002f6790609f4a3eef7f42069d3)
2012-01-16 14:10:32 +00:00
zzz
404578515b bundle jmx 2012-01-14 22:20:39 +00:00
zzz
fd6fcda781 fixup after prop 2012-01-14 18:08:26 +00:00
zzz
23ca49ea8e propagate from branch 'i2p.i2p' (head b3d611a1fe034bc89963c54179d5bef3a3147950)
to branch 'i2p.i2p.zzz.jetty6' (head c83bf7bd62d0e07be0d965f062f01b01864be4d2)
2012-01-14 18:04:39 +00:00
zzz
edf5ef588d remove dup docs from tomcat jars 2012-01-10 20:17:35 +00:00
zzz
405c24b0e3 Add JSP 2.1 trim white space directive to all jsps to save a few KB 2012-01-10 13:21:35 +00:00
zzz
1b85c22ffc escape quotes 2012-01-10 04:10:14 +00:00
zzz
8e20e7a5b5 propagate from branch 'i2p.i2p' (head 96b4e09e85e0947d0b9df188f4861664073f07a6)
to branch 'i2p.i2p.zzz.jetty6' (head 4024ef4f6e6c5e4ca6a7803614dc769ca654ac5f)
2012-01-10 04:06:23 +00:00
zzz
3024b3fd3b * Move from Servlet 2.4/JSP 2.0 to Servlet 2.5/JSP 2.1
- Replace Jasper 2.0 from Jetty 6 with Apache Tomcat 6.0.35 (CDDL 1.0 + GPLv2)
  - Replace JSTL 1.1.2 with JSTL 1.2 (CDDL 1.0 + GPLv2)
2012-01-10 04:03:30 +00:00
zzz
51f7f3a378 log all jetty warns as errors 2012-01-10 03:40:53 +00:00
zzz
7feaadbd7d fixup after prop 2012-01-08 15:01:35 +00:00
zzz
69bbb88407 propagate from branch 'i2p.i2p' (head b7ee04ecc7a594239e977b25a52ebdabadce558e)
to branch 'i2p.i2p.zzz.jetty6' (head 2cd4a4dae8b87b9ed2128d83aff1b39e3a818556)
2012-01-08 14:55:10 +00:00
zzz
43ec87e412 - i2ptunnel: Move bean classes from the jar to the war.
External usage was deprecated about a year ago.
  This will break old seedless plugins.
2012-01-04 15:22:01 +00:00
zzz
a14643f710 fix eepsite migration in packages 2012-01-04 15:20:35 +00:00
kytv
0ad4789ff2 Add jetty-rewrite-handler.jar to the Debian packaging 2012-01-02 02:04:51 +00:00
kytv
dd9cae57a8 merge of '83079d347b764886d77d9d9de902011f09f5dcce'
and 'c76215859aa3b76a04c4a83a1ded20548a8773a6'
2012-01-02 00:59:33 +00:00
kytv
84e4558d7d Updated packaging scripts to work with Debian's (and Ubuntu's) Jetty packages. 2012-01-01 23:31:41 +00:00
zzz
33b25b5780 - Fix jetty.xml migrate quote handling
- Fix I2PRequestLog javadoc
- Rename jetty-threadpool.jar to jetty-java5-threadpool.jar to match ubuntu symlink
- Bundle jetty-rewrite-handler.jar (20KB) and .xml config to
  make it easier to do rewrites (unused by I2P)
2012-01-01 17:57:59 +00:00
zzz
b5f97d0883 - Fix jetty.xml copy bug
- Fix NPE logging error when Router.saveConfig() fails early
- Log readConfig() and saveConfig() errors to wrapper log if
  router log not yet available
- Handle non-split configuration in MigrateJetty
- Better logging of migration errors
- Handle existing backup files during migration better
2011-12-31 14:38:37 +00:00
zzz
beb6d1f43f I2PLogger fix; better log init 2011-12-31 00:49:39 +00:00
zzz
c0662bc111 license update 2011-12-31 00:06:23 +00:00
zzz
327f38b535 fix JettyFixes target 2011-12-30 23:34:18 +00:00
zzz
4d1736eaf6 jetty logging tweaks 2011-12-30 21:58:16 +00:00
zzz
03e86fcb24 make jetty use I2P logging 2011-12-30 19:44:57 +00:00
zzz
be7623a462 - Start webapps after console for faster startup
- Add delay in systray port checker to ensure console is up
- Move I2PRequestLog to net.i2p.jetty package
2011-12-29 23:25:27 +00:00
kytv
07162b56c8 escape quotation marks in jsp files
The routerconsole's precompilejsp target failed when using the jetty packages
from Debian. These escaped jsp files also work with 'our' jetty6 (and jetty6).
2011-12-25 22:37:30 +00:00
zzz
ec7ec564be - Fix Console concurrent ThreadPool
- Uncomment eepsite concurrent ThreadPool and fix arguments
- Reduce eepsite acceptors to 1
- Add jetty-ssl.xml example
- jetty.xml cleanup
2011-12-24 17:09:01 +00:00
zzz
0fb9096096 - Fix help.jsp mapping to language
- Fix nowebapp.jsp for non-started webapps
- Fix nowebapp.jsp for url /foo for non-started webapp foo
2011-12-24 05:26:56 +00:00
zzz
5a4becba68 updater200WithJetty target 2011-12-23 22:00:16 +00:00
zzz
2083d8c6a6 basic jetty.xml migration tool 2011-12-23 21:27:38 +00:00
zzz
8ea587accb fix up-to-date check 2011-12-23 15:41:05 +00:00
zzz
d976b59732 fix getWebApp() 2011-12-23 15:36:44 +00:00
zzz
41ea29209f eepsite:
- fix cgi-bin
  - enable WebAppDeplyer
  - add webdefault.xml
2011-12-23 15:17:34 +00:00
zzz
fbbab0d819 mods to compile with Jetty 6 2011-12-23 01:01:40 +00:00
zzz
56901e5ff7 base files from Jetty 5.1.15 for reference 2011-12-23 01:00:45 +00:00
zzz
04cbcf2759 reapply I2P mods 2011-12-23 00:58:13 +00:00
zzz
99ad70e80a 6.1.26 base for reference 2011-12-23 00:57:46 +00:00
zzz
92b9d0a996 First cut at migrating to Jetty 6 and prep for using an external
Jetty 6 package.

- Add several jars from the Jetty 6 distribution
- Update jetty.xml
- Add context XML files
- Update WorkingDir to migrate the content XML files
- Update RouterConsoleRunner and LocaleWebAppHandler
- Remove all old Jetty 5.1.15 local mods;
  this will break Seedless using a custom Server() constructor
- Update I2PRequestLog to be a mod of NCSARequestLog from 6.1.26
- Put I2PRequestLog in its own jar
- Copy MultiPartRequest and other required classes from Jetty 5.1.15
  and add it to susimail, as the replacement MultiPartFilter in
  Jetty 6 is difficult to migrate to, and does not support content-type
- Update i2psnark for Jetty 6
- Disable i2psnark RunStandalone, unused and instantiated Jetty 5
- Fix up all webapp build.xml to reference new jars

Not yet working: Plugin/webapp run detection and stopping, eepsite CGI
Not well tested: Plugins, classpaths, webapps
2011-12-23 00:56:48 +00:00
zzz
d8080278b3 initial DHT code, needs work 2011-02-06 00:12:54 +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
1466 changed files with 172780 additions and 155262 deletions

View File

@@ -17,10 +17,10 @@ _jsp\.java$
\.war$
\.zip$
^\.
^build/
^build
^pkg-temp/
~$
/build/
/build
/classes/
^debian/copyright
override.properties

View File

@@ -7,8 +7,10 @@ trans.da = apps/i2ptunnel/locale/messages_da.po
trans.de = apps/i2ptunnel/locale/messages_de.po
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.nl = apps/i2ptunnel/locale/messages_nl.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
@@ -22,13 +24,16 @@ trans.ar = apps/routerconsole/locale/messages_ar.po
trans.cs = apps/routerconsole/locale/messages_cs.po
trans.da = apps/routerconsole/locale/messages_da.po
trans.de = apps/routerconsole/locale/messages_de.po
trans.et_EE = apps/routerconsole/locale/messages_ee.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.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.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
@@ -43,6 +48,7 @@ trans.cs = apps/i2psnark/locale/messages_cs.po
trans.de = apps/i2psnark/locale/messages_de.po
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.nl = apps/i2psnark/locale/messages_nl.po
trans.pl = apps/i2psnark/locale/messages_pl.po
@@ -59,11 +65,14 @@ trans.ar = apps/susidns/locale/messages_ar.po
trans.cs = apps/susidns/locale/messages_cs.po
trans.da = apps/susidns/locale/messages_da.po
trans.de = apps/susidns/locale/messages_de.po
trans.el = apps/susidns/locale/messages_el.po
trans.es = apps/susidns/locale/messages_es.po
trans.fr = apps/susidns/locale/messages_fr.po
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
@@ -77,8 +86,10 @@ trans.ar = apps/desktopgui/locale/messages_ar.po
trans.cs = apps/desktopgui/locale/messages_cs.po
trans.da = apps/desktopgui/locale/messages_da.po
trans.de = apps/desktopgui/locale/messages_de.po
trans.el = apps/desktopgui/locale/messages_el.po
trans.es = apps/desktopgui/locale/messages_es.po
trans.fr = apps/desktopgui/locale/messages_fr.po
trans.hu = apps/desktopgui/locale/messages_hu.po
trans.it = apps/desktopgui/locale/messages_it.po
trans.nl = apps/desktopgui/locale/messages_nl.po
trans.pl = apps/desktopgui/locale/messages_pl.po
@@ -95,6 +106,7 @@ trans.cs = apps/susimail/locale/messages_cs.po
trans.de = apps/susimail/locale/messages_de.po
trans.es = apps/susimail/locale/messages_es.po
trans.fr = apps/susimail/locale/messages_fr.po
trans.hu = apps/susimail/locale/messages_hu.po
trans.it = apps/susimail/locale/messages_it.po
trans.nl = apps/susimail/locale/messages_nl.po
trans.ru = apps/susimail/locale/messages_ru.po
@@ -109,7 +121,11 @@ source_file = debian/po/templates.pot
source_lang = en
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
trans.ru = debian/po/ru.po
trans.sv_SE = debian/po/sv.po

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

@@ -79,11 +79,13 @@ Public domain except as listed below:
From freenet
See licenses/LICENSE-GPLv2.txt
UPnP subsystem 1.7:
Copyright (C) 2003-2006 Satoshi Konno
UPnP subsystem (CyberLink) 2.1:
Copyright (C) 2003-2010 Satoshi Konno
See licenses/LICENSE-UPnP.txt
GeoIP data free to use, courtesy http://www.maxmind.com/
GeoIP: GeoLite databases are licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
http://creativecommons.org/licenses/by-sa/3.0/
This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/
Installer:
@@ -172,8 +174,9 @@ Applications:
By welterde.
See licenses/LICENSE-GPLv2.txt
Jetty 5.1.15:
Copyright 2000-2004 Mort Bay Consulting Pty. Ltd.
Jetty 6.1.26:
Copyright 1995-2009 Mort Bay Consulting Pty Ltd
See licenses/LICENSE-Jetty.txt
See licenses/LICENSE-Apache2.0.txt
See licenses/NOTICE-Commons-Logging.txt
@@ -196,6 +199,7 @@ Applications:
- Guernsey and Isle of Man flags from the Open Clip Art Library, 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
GeoIP Data:
Copyright (c) 2008 MaxMind, Inc. All Rights Reserved.
@@ -205,6 +209,10 @@ Applications:
"Man with hat over face" & related images licensed under a Creative Commons 2.0 license.
Original photos by Florian Kuhlmann. http://www.flickr.com/photos/floriankuhlmann/3117758155
I2PSnark light theme:
"Creative Commons Cat" licensed under a Creative Commons Attribution 3.0 Unported License.
Original photo by Boaz Arad. http://www.luxphile.com/2011/01/creative-commons-cat.html
SAM:
Public domain.
@@ -215,8 +223,10 @@ Applications:
Copyright (C) 2005 <susi23@mail.i2p>
GPLv2 (or any later version)
See licenses/LICENSE-GPLv2.txt
Uses Apache Jakarta Standard Tag Library 1.1.2:
See licenses/LICENSE-Apache2.0.txt
Uses Glassfish Standard Tag Library (JSTL) 1.2:
Common Development and Distribution License (CDDL) version 1.0 + GNU General Public License (GPL) version 2
See https://glassfish.dev.java.net/public/CDDL+GPL.html
See licenses/LICENSE-GPLv2.txt
SusiMail:
Copyright (C) 2004-2005 <susi23@mail.i2p>
@@ -228,6 +238,10 @@ Applications:
Bundles systray4j-2.4.1:
See licenses/LICENSE-LGPLv2.1.txt
Tomcat 6.0.35:
Copyright 1999-2011 The Apache Software Foundation
See licenses/LICENSE-Apache2.0.txt
See licenses/NOTICE-Tomcat.txt
Other Applications and Libraries

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

@@ -26,9 +26,9 @@ for i in *.config ; {
( cd $INST_DIR/eepsite
if [ -f jetty.xml ] ; then
rm jetty.xml.new
echo "Please check ${INST_DIR}/eepsite, as there are new files."
else
mv jetty.xml.new jetty.xml
find $PKG/$INSTALL_DIR/i2p -name "*.xml.new" -exec sh -c 'mv "$0" "${0/.new}"' {} \;
fi
)

View File

@@ -18,6 +18,7 @@
#
BUILD=1sponge
# INSTALL_DIR is referenced from /, don't prefix it with a '/'
INSTALL_DIR=opt
NAME=i2p
ARCH=noarch
@@ -104,7 +105,10 @@ sed "s|%INSTALL_PATH|/$INSTALL_DIR/i2p|g" runplain.sh > a
sed "s|%SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" a > runplain.sh
# i2prouter %INSTALL_PATH and %SYSTEM_java_io_tmpdir
sed "s|%INSTALL_PATH|/$INSTALL_DIR/i2p|g" i2prouter > a
sed "s|%SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" a > i2prouter
rm i2prouter
mv a i2prouter
sed "s|%SYSTEM_java_io_tmpdir|/$INSTALL_DIR/i2p|g" i2prouter > a
sed "s|#ALLOW_ROOT=true|ALLOW_ROOT=true|g" a > i2prouter
chmod 744 ./i2prouter
chmod 744 ./osid
@@ -116,7 +120,7 @@ rm -Rf ./lib/*.dll ./*.bat ./*.exe ./installer ./icons ./a postinstall.sh
mv $PKG/$INSTALL_DIR/i2p/*.config $PKG/install
mv $PKG/$INSTALL_DIR/i2p/blocklist.txt $PKG/$INSTALL_DIR/i2p/blocklist.txt.new
mv $PKG/$INSTALL_DIR/i2p/eepsite/jetty.xml $PKG/$INSTALL_DIR/i2p/eepsite/jetty.xml.new
find $PKG/$INSTALL_DIR/i2p -name "*.xml" -exec mv {} {}.new \;
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html.new
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico.new
sed "s|directory|/$INSTALL_DIR/i2p/|g" $CWD/doinst.sh > $PKG/install/doinst.sh
@@ -124,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

@@ -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;
@@ -38,7 +30,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import net.i2p.I2PAppContext;
import net.i2p.client.I2PClient;
import net.i2p.client.streaming.RetransmissionTimer;
import net.i2p.util.Log;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer2;
@@ -116,7 +107,6 @@ import net.i2p.util.SimpleTimer2;
*/
public class BOB {
private final static Log _log = new Log(BOB.class);
public final static String PROP_CONFIG_LOCATION = "BOB.config";
public final static String PROP_BOB_PORT = "BOB.port";
public final static String PROP_BOB_HOST = "BOB.host";
@@ -138,7 +128,7 @@ public class BOB {
*/
public static void info(String arg) {
System.out.println("INFO:" + arg);
_log.info(arg);
(new Log(BOB.class)).info(arg);
}
/**
@@ -148,7 +138,7 @@ public class BOB {
*/
public static void warn(String arg) {
System.out.println("WARNING:" + arg);
_log.warn(arg);
(new Log(BOB.class)).warn(arg);
}
/**
@@ -158,7 +148,7 @@ public class BOB {
*/
public static void error(String arg) {
System.out.println("ERROR: " + arg);
_log.error(arg);
(new Log(BOB.class)).error(arg);
}
/**
@@ -182,12 +172,11 @@ public class BOB {
// Re-reading the config file in each thread is pretty damn stupid.
String configLocation = System.getProperty(PROP_CONFIG_LOCATION, "bob.config");
// This is here just to ensure there is no interference with our threadgroups.
RetransmissionTimer Y = RetransmissionTimer.getInstance();
SimpleScheduler Y1 = SimpleScheduler.getInstance();
SimpleTimer2 Y2 = SimpleTimer2.getInstance();
i = Y.hashCode();
i = Y1.hashCode();
i = Y2.hashCode();
Log _log = new Log(BOB.class);
try {
{
File cfg = new File(configLocation);
@@ -263,6 +252,7 @@ public class BOB {
i = 0;
boolean g = false;
spin.set(true);
try {
info("BOB is now running.");
listener = new ServerSocket(Integer.parseInt(props.getProperty(PROP_BOB_PORT)), 10, InetAddress.getByName(props.getProperty(PROP_BOB_HOST)));

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;
@@ -54,7 +46,7 @@ public class DoCMDS implements Runnable {
// FIX ME
// I need a better way to do versioning, but this will do for now.
public static final String BMAJ = "00", BMIN = "00", BREV = "0F", BEXT = "";
public static final String BMAJ = "00", BMIN = "00", BREV = "10", BEXT = "";
public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT;
private Socket server;
private Properties props;
@@ -400,7 +392,7 @@ public class DoCMDS implements Runnable {
*/
private boolean is64ok(String data) {
try {
Destination x = new Destination(data);
new Destination(data);
return true;
} catch (Exception e) {
return false;

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;
@@ -41,7 +33,6 @@ public class I2Plistener implements Runnable {
private NamedDB info, database;
private Log _log;
// private int tgwatch;
public I2PSocketManager socketManager;
public I2PServerSocket serverSocket;
private AtomicBoolean lives;
@@ -95,7 +86,7 @@ public class I2Plistener implements Runnable {
}
} catch (I2PException e) {
// bad shit
// bad stuff
System.out.println("Exception " + e);
}
} finally {
@@ -103,7 +94,7 @@ public class I2Plistener implements Runnable {
serverSocket.close();
} catch (I2PException ex) {
}
// System.out.println("I2Plistener: Close");
// System.out.println("I2Plistener: Close");
}
}
}

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;
@@ -108,16 +100,6 @@ public class MUXlisten implements Runnable {
this.listener = new ServerSocket(port, backlog, host);
}
socketManager = I2PSocketManagerFactory.createManager(prikey, Q);
// I2PException, IOException, RuntimeException
// To bad we can't just catch and enumerate....
// } catch (I2PException e) {
// Something went bad.
// this.database.getWriteLock();
// this.info.getWriteLock();
// this.info.add("STARTING", new Boolean(false));
// this.info.releaseWriteLock();
// this.database.releaseWriteLock();
// throw new I2PException(e);
} catch (IOException e) {
// Something went bad.
this.database.getWriteLock();
@@ -194,7 +176,6 @@ public class MUXlisten implements Runnable {
lock.set(false);
return;
}
// socketManager.addDisconnectListener(new DisconnectListener());
lives.set(true);
lock.set(false);
quit:
@@ -313,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());
}
}
@@ -344,26 +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);
// tg.interrupt(); // give my stuff a small smack again.
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 {
@@ -373,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,11 +11,10 @@
* 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;
import net.i2p.client.streaming.RetransmissionTimer;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer2;
@@ -40,7 +31,6 @@ public class Main {
*/
public static void main(String[] args) {
// THINK THINK THINK THINK THINK THINK
RetransmissionTimer Y = RetransmissionTimer.getInstance();
SimpleScheduler Y1 = SimpleScheduler.getInstance();
SimpleTimer2 Y2 = SimpleTimer2.getInstance();
@@ -48,6 +38,5 @@ public class Main {
Y2.stop();
Y1.stop();
Y.stop();
}
}

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;
@@ -95,14 +87,9 @@ public class TCPio implements Runnable {
if (b > 0) {
Aout.write(a, 0, b);
} else if (b == 0) {
// Will this die? We'll see.
while(Ain.available() == 0) {
Thread.sleep(20);
}
// Thread.yield(); // this should act like a mini sleep.
// if (Ain.available() == 0) {
// Thread.sleep(10);
// }
} else {
/* according to the specs:
*

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;
@@ -27,8 +19,6 @@ import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
// import net.i2p.client.I2PSession;
// import net.i2p.client.I2PSessionException;
import java.util.concurrent.atomic.AtomicBoolean;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocketManager;

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;
@@ -108,20 +100,18 @@ public class TCPtoI2P implements Runnable {
* @throws java.io.IOException
*/
private void Emsg(String e, OutputStream out) throws IOException {
// Debugging System.out.println("ERROR TCPtoI2P: " + e);
// Debugging System.out.println("ERROR TCPtoI2P: " + e);
out.write("ERROR ".concat(e).getBytes());
out.write(13);
out.write(10);
out.flush();
}
// private void rlock() throws Exception {
private void rlock() {
database.getReadLock();
info.getReadLock();
}
// private void runlock() throws Exception {
private void runlock() {
info.releaseReadLock();
database.releaseReadLock();

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;
@@ -111,7 +103,7 @@ public class UDPIOthread implements I2PSessionListener, Runnable {
* @param size
*/
public void messageAvailable(I2PSession session, int msgId, long size) {
// _log.debug("Message available: id = " + msgId + " size = " + size);
// _log.debug("Message available: id = " + msgId + " size = " + size);
try {
byte msg[] = session.receiveMessage(msgId);
out.write(msg);

View File

@@ -56,6 +56,7 @@
<manifest>
<attribute name="Main-Class" value="addressbook.Daemon"/>
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />
<attribute name="Base-Revision" value="${workspace.version}" />
<attribute name="Workspace-Changes" value="${workspace.changes}" />
@@ -75,6 +76,7 @@
<war basedir="${dist}/tmp" webxml="web.xml" destfile="${dist}/${war}">
<manifest>
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />
<attribute name="Base-Revision" value="${workspace.version}" />
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />

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,16 +75,16 @@ 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);
this.thread.setDaemon(true);
this.thread.setName("Addressbook");
this.thread.start();
System.out.println("INFO: Starting Addressbook " + Daemon.VERSION);
//System.out.println("INFO: Starting Addressbook " + Daemon.VERSION);
//System.out.println("INFO: config root under " + args[0]);
}

View File

@@ -26,7 +26,6 @@ import java.util.Iterator;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper; // debug
/**
* An iterator over the subscriptions in a SubscriptionList. Note that this iterator

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

@@ -0,0 +1,56 @@
# I2P
# Copyright (C) 2009 The I2P Project
# This file is distributed under the same license as the desktopgui package.
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# <lixtetrax@grhack.net>, 2012.
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
"PO-Revision-Date: 2012-07-02 11:28+0000\n"
"Last-Translator: lixtetrax <lixtetrax@grhack.net>\n"
"Language-Team: Greek (http://www.transifex.com/projects/p/I2P/language/el/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: el\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
msgid "Start I2P"
msgstr "Έναρξη Ι2Ρ"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
msgid "I2P is starting!"
msgstr "Το Ι2Ρ ξεκίνησε!"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
msgid "Starting"
msgstr "Έναρξη"
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
msgid "Launch I2P Browser"
msgstr "Έναρξη φυλλομετρητή Ι2Ρ"
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
msgid "Configure desktopgui"
msgstr "Παραμετροποίηση desktopgui"
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
msgid "Restart I2P"
msgstr "Επανεκκίνηση Ι2Ρ"
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
msgid "Stop I2P"
msgstr "Τερματισμός Ι2Ρ"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
msgid "Tray icon configuration"
msgstr "Παραμετροποίηση εικονιδίου"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
msgid "Should tray icon be enabled?"
msgstr "Ενεργοποίηση εικονιδίου;"

View File

@@ -0,0 +1,55 @@
# I2P
# Copyright (C) 2009 The I2P Project
# This file is distributed under the same license as the desktopgui package.
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
"PO-Revision-Date: 2012-06-01 16:28+0000\n"
"Last-Translator: AdminLMH <lehetmashogy@i2pmail.org>\n"
"Language-Team: Hungarian (http://www.transifex.net/projects/p/I2P/language/hu/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: hu\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
msgid "Start I2P"
msgstr "I2P indítása"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
msgid "I2P is starting!"
msgstr "I2P indul!"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:38
msgid "Starting"
msgstr "indítás"
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
msgid "Launch I2P Browser"
msgstr "I2P Böngésző Indítása"
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
msgid "Configure desktopgui"
msgstr "Asztali Grafikus Felület Beállítása"
#: src/net/i2p/desktopgui/InternalTrayManager.java:67
msgid "Restart I2P"
msgstr "I2P Újraindítása"
#: src/net/i2p/desktopgui/InternalTrayManager.java:85
msgid "Stop I2P"
msgstr "I2P Leállítása"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
msgid "Tray icon configuration"
msgstr "Tálcaikon beállítása"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
msgid "Should tray icon be enabled?"
msgstr "Tálcaikon engedélyezve legyen?"

View File

@@ -3,15 +3,17 @@
# This file is distributed under the same license as the desktopgui package.
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# <bovas85@gmail.com>, 2012.
# <jokjok@hotmail.it>, 2011.
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
"PO-Revision-Date: 2011-06-09 17:09+0000\n"
"Last-Translator: mkkid <jokjok@hotmail.it>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/I2P/team/it/)\n"
"PO-Revision-Date: 2012-06-01 12:21+0000\n"
"Last-Translator: Leelium <bovas85@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.net/projects/p/I2P/language/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -48,10 +50,8 @@ msgstr "Ferma I2P"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
msgid "Tray icon configuration"
msgstr "Configurazione dell'icona nell'Area di notifica"
msgstr "Configurazione dell'icona nell'area di notifica"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
msgid "Should tray icon be enabled?"
msgstr "Vuoi che l'icona nell'Area di notifica venga abilitata?"
msgstr "Vuoi che l'icona nelll'rea di notifica venga abilitata?"

View File

@@ -3,7 +3,8 @@
# This file is distributed under the same license as the desktopgui package.
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# 123hund123 <M8R-ra4r1r@mailinator.com>, 2011
# Translators:
# 123hund123 <M8R-ra4r1r@mailinator.com>, 2011.
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
@@ -11,7 +12,7 @@ msgstr ""
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
"PO-Revision-Date: 2011-03-22 15:49+0000\n"
"Last-Translator: 123hund123 <M8R-ra4r1r@mailinator.com>\n"
"Language-Team: Swedish (Sweden) (http://www.transifex.net/projects/p/I2P/team/sv_SE/)\n"
"Language-Team: Swedish (Sweden) (http://www.transifex.net/projects/p/I2P/language/sv_SE/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -53,5 +54,3 @@ msgstr "Ikonpanelskonfiguration"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
msgid "Should tray icon be enabled?"
msgstr "Ska ikonpanelen vara aktiverad?"

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

Before

Width:  |  Height:  |  Size: 464 B

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

View File

Before

Width:  |  Height:  |  Size: 587 B

After

Width:  |  Height:  |  Size: 587 B

View File

Before

Width:  |  Height:  |  Size: 673 B

After

Width:  |  Height:  |  Size: 673 B

View File

Before

Width:  |  Height:  |  Size: 882 B

After

Width:  |  Height:  |  Size: 882 B

View File

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 889 B

View File

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 766 B

View File

Before

Width:  |  Height:  |  Size: 653 B

After

Width:  |  Height:  |  Size: 653 B

View File

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 537 B

View File

Before

Width:  |  Height:  |  Size: 578 B

After

Width:  |  Height:  |  Size: 578 B

View File

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 591 B

View File

Before

Width:  |  Height:  |  Size: 385 B

After

Width:  |  Height:  |  Size: 385 B

View File

Before

Width:  |  Height:  |  Size: 853 B

After

Width:  |  Height:  |  Size: 853 B

View File

Before

Width:  |  Height:  |  Size: 635 B

After

Width:  |  Height:  |  Size: 635 B

View File

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 294 B

View File

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 591 B

View File

Before

Width:  |  Height:  |  Size: 589 B

After

Width:  |  Height:  |  Size: 589 B

View File

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 591 B

View File

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 537 B

View File

@@ -19,6 +19,7 @@
<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-util.jar" />
</classpath>
</depend>
</target>
@@ -34,7 +35,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:../../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-util.jar:../../ministreaming/java/build/mstreaming.jar" >
<compilerarg line="${javac.compilerargs}" />
</javac>
</target>
@@ -56,11 +57,12 @@
<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 **/messages_*.class">
<jar destfile="./build/i2psnark.jar" basedir="./build/obj" includes="**/*.class" excludes="**/I2PSnarkServlet*.class **/FetchAndAdd*.class **/messages_*.class">
<manifest>
<attribute name="Main-Class" value="org.klomp.snark.Snark" />
<attribute name="Class-Path" value="i2p.jar mstreaming.jar streaming.jar" />
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />
<attribute name="Base-Revision" value="${workspace.version}" />
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
@@ -70,7 +72,7 @@
<target name="jarUpToDate">
<uptodate property="jar.uptodate" targetfile="build/i2psnark.jar" >
<srcfiles dir= "build/obj" includes="**/*.class" excludes="**/I2PSnarkServlet*.class **/messages_*.class" />
<srcfiles dir= "build/obj" includes="**/*.class" excludes="**/I2PSnarkServlet*.class **/FetchAndAdd*.class **/messages_*.class" />
</uptodate>
<condition property="shouldListChanges" >
<and>
@@ -78,7 +80,7 @@
<isset property="jar.uptodate" />
</not>
<not>
<isset property="wjar.uptodate" />
<isset property="war.uptodate" />
</not>
<isset property="mtn.available" />
</and>
@@ -95,11 +97,16 @@
<target name="war" depends="jar, bundle, warUpToDate, listChangedFiles" unless="war.uptodate" >
<!-- set if unset -->
<property name="workspace.changes.tr" value="" />
<war destfile="../i2psnark.war" webxml="../web.xml" basedir="../" includes="_icons/*" >
<copy todir="build/icons/.icons" >
<fileset dir="../icons/" />
</copy>
<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" />
<fileset dir="build/icons/" />
<manifest>
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />
<attribute name="Base-Revision" value="${workspace.version}" />
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
@@ -109,7 +116,7 @@
<target name="warUpToDate">
<uptodate property="war.uptodate" targetfile="../i2psnark.war" >
<srcfiles dir= "." includes="build/obj/org/klomp/snark/web/*.class ../_icons/* ../web.xml" />
<srcfiles dir= "." includes="build/obj/org/klomp/snark/web/*.class ../icons/* ../web.xml" />
</uptodate>
</target>

View File

@@ -0,0 +1,76 @@
package net.i2p.kademlia;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.util.Set;
import net.i2p.data.SimpleDataStructure;
/**
* Group, without inherent ordering, a set of keys a certain distance away from
* a local key, using XOR as the distance metric
*
* Refactored from net.i2p.router.networkdb.kademlia
* @since 0.9.2
*/
public interface KBucket<T extends SimpleDataStructure> {
/**
* Lowest order high bit for difference keys.
* The lower-bounds distance of this bucket is 2**begin.
* If begin == 0, this is the closest bucket.
*/
public int getRangeBegin();
/**
* Highest high bit for the difference keys.
* The upper-bounds distance of this bucket is (2**(end+1)) - 1.
* If begin == end, the bucket cannot be split further.
* If end == (numbits - 1), this is the furthest bucket.
*/
public int getRangeEnd();
/**
* Number of keys already contained in this kbucket
*/
public int getKeyCount();
/**
* Add the peer to the bucket
*
* @return true if added
*/
public boolean add(T key);
/**
* Remove the key from the bucket
* @return true if the key existed in the bucket before removing it, else false
*/
public boolean remove(T key);
/**
* Update the last-changed timestamp to now.
*/
public void setLastChanged();
/**
* The last-changed timestamp
*/
public long getLastChanged();
/**
* Retrieve all routing table entries stored in the bucket
* @return set of Hash structures
*/
public Set<T> getEntries();
public void getEntries(SelectionCollector<T> collector);
public void clear();
}

View File

@@ -0,0 +1,150 @@
package net.i2p.kademlia;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.util.Collections;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.SimpleDataStructure;
import net.i2p.util.ConcurrentHashSet;
/**
* A concurrent implementation using ConcurrentHashSet.
* The max size (K) may be temporarily exceeded due to concurrency,
* a pending split, or the behavior of the supplied trimmer,
* as explained below.
* The creator is responsible for splits.
*
* This class has no knowledge of the DHT base used for XORing,
* and thus there are no validity checks in add/remove.
*
* The begin and end values are immutable.
* All entries in this bucket will have at least one bit different
* from us in the range [begin, end] inclusive.
* Splits must be implemented by creating two new buckets
* and discarding this one.
*
* The keys are kept in a Set and are NOT sorted by last-seen.
* Per-key last-seen-time, failures, etc. must be tracked elsewhere.
*
* If this bucket is full (i.e. begin == end && size == max)
* then add() will call KBucketTrimmer.trim() do
* (possibly) remove older entries, and indicate whether
* to add the new entry. If the trimmer returns true without
* removing entries, this KBucket will exceed the max size.
*
* Refactored from net.i2p.router.networkdb.kademlia
* @since 0.9.2
*/
class KBucketImpl<T extends SimpleDataStructure> implements KBucket<T> {
/**
* set of Hash objects for the peers in the kbucket
*/
private final Set<T> _entries;
/** include if any bits equal or higher to this bit (in big endian order) */
private final int _begin;
/** include if no bits higher than this bit (inclusive) are set */
private final int _end;
private final int _max;
private final KBucketTrimmer _trimmer;
/** when did we last shake things up */
private long _lastChanged;
private final I2PAppContext _context;
/**
* All entries in this bucket will have at least one bit different
* from us in the range [begin, end] inclusive.
*/
public KBucketImpl(I2PAppContext context, int begin, int end, int max, KBucketTrimmer trimmer) {
if (begin > end)
throw new IllegalArgumentException(begin + " > " + end);
_context = context;
_entries = new ConcurrentHashSet(max + 4);
_begin = begin;
_end = end;
_max = max;
_trimmer = trimmer;
}
public int getRangeBegin() { return _begin; }
public int getRangeEnd() { return _end; }
public int getKeyCount() {
return _entries.size();
}
/**
* @return an unmodifiable view; not a copy
*/
public Set<T> getEntries() {
return Collections.unmodifiableSet(_entries);
}
public void getEntries(SelectionCollector<T> collector) {
for (T h : _entries) {
collector.add(h);
}
}
public void clear() {
_entries.clear();
}
/**
* Sets last-changed if rv is true OR if the peer is already present.
* Calls the trimmer if begin == end and we are full.
* If begin != end then add it and caller must do bucket splitting.
* @return true if added
*/
public boolean add(T peer) {
if (_begin != _end || _entries.size() < _max ||
_entries.contains(peer) || _trimmer.trim(this, peer)) {
// do this even if already contains, to call setLastChanged()
boolean rv = _entries.add(peer);
setLastChanged();
return rv;
}
return false;
}
/**
* @return if removed. Does NOT set lastChanged.
*/
public boolean remove(T peer) {
boolean rv = _entries.remove(peer);
//if (rv)
// setLastChanged();
return rv;
}
/**
* Update the last-changed timestamp to now.
*/
public void setLastChanged() {
_lastChanged = _context.clock().now();
}
/**
* The last-changed timestamp, which actually indicates last-added or last-seen.
*/
public long getLastChanged() {
return _lastChanged;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(1024);
buf.append(_entries.size());
buf.append(" entries in (").append(_begin).append(',').append(_end);
buf.append(") : ").append(_entries.toString());
return buf.toString();
}
}

View File

@@ -0,0 +1,780 @@
package net.i2p.kademlia;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
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;
/**
* In-memory storage of buckets sorted by the XOR metric from the base (us)
* passed in via the constructor.
* This starts with one bucket covering the whole key space, and
* may eventually be split to a max of the number of bits in the data type
* (160 for SHA1Hash or 256 for Hash),
* times 2**(B-1) for Kademlia value B.
*
* Refactored from net.i2p.router.networkdb.kademlia
* @since 0.9.2
*/
public class KBucketSet<T extends SimpleDataStructure> {
private final Log _log;
private final I2PAppContext _context;
private final T _us;
/**
* The bucket list is locked by _bucketsLock, however the individual
* buckets are not locked. Users may see buckets that have more than
* the maximum k entries, or may have adds and removes silently fail
* when they appear to succeed.
*
* Closest values are in bucket 0, furthest are in the last bucket.
*/
private final List<KBucket> _buckets;
private final Range<T> _rangeCalc;
private final KBucketTrimmer _trimmer;
/**
* Locked for reading only when traversing all the buckets.
* Locked for writing only when splitting a bucket.
* Adds/removes/gets from individual buckets are not locked.
*/
private final ReentrantReadWriteLock _bucketsLock = new ReentrantReadWriteLock(false);
private final int KEYSIZE_BITS;
private final int NUM_BUCKETS;
private final int BUCKET_SIZE;
private final int B_VALUE;
private final int B_FACTOR;
/**
* Use the default trim strategy, which removes a random entry.
* @param us the local identity (typically a SHA1Hash or Hash)
* The class must have a zero-argument constructor.
* @param max the Kademlia value "k", the max per bucket, k >= 4
* @param b the Kademlia value "b", split buckets an extra 2**(b-1) times,
* b > 0, use 1 for bittorrent, Kademlia paper recommends 5
*/
public KBucketSet(I2PAppContext context, T us, int max, int b) {
this(context, us, max, b, new RandomTrimmer(context, max));
}
/**
* Use the supplied trim strategy.
*/
public KBucketSet(I2PAppContext context, T us, int max, int b, KBucketTrimmer trimmer) {
_us = us;
_context = context;
_log = context.logManager().getLog(KBucketSet.class);
_trimmer = trimmer;
if (max <= 4 || b <= 0 || b > 8)
throw new IllegalArgumentException();
KEYSIZE_BITS = us.length() * 8;
B_VALUE = b;
B_FACTOR = 1 << (b - 1);
NUM_BUCKETS = KEYSIZE_BITS * B_FACTOR;
BUCKET_SIZE = max;
_buckets = createBuckets();
_rangeCalc = new Range(us, B_VALUE);
// this verifies the zero-argument constructor
makeKey(new byte[us.length()]);
}
private void getReadLock() {
_bucketsLock.readLock().lock();
}
/**
* Get the lock if we can. Non-blocking.
* @return true if the lock was acquired
*/
private boolean tryReadLock() {
return _bucketsLock.readLock().tryLock();
}
private void releaseReadLock() {
_bucketsLock.readLock().unlock();
}
/** @return true if the lock was acquired */
private boolean getWriteLock() {
try {
boolean rv = _bucketsLock.writeLock().tryLock(3000, TimeUnit.MILLISECONDS);
if ((!rv) && _log.shouldLog(Log.WARN))
_log.warn("no lock, size is: " + _bucketsLock.getQueueLength(), new Exception("rats"));
return rv;
} catch (InterruptedException ie) {}
return false;
}
private void releaseWriteLock() {
_bucketsLock.writeLock().unlock();
}
/**
* @return true if the peer is new to the bucket it goes in, or false if it was
* already in it. Always returns false on an attempt to add ourselves.
*
*/
public boolean add(T peer) {
KBucket bucket;
getReadLock();
try {
bucket = getBucket(peer);
} finally { releaseReadLock(); }
if (bucket != null) {
if (bucket.add(peer)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Peer " + peer + " added to bucket " + bucket);
if (shouldSplit(bucket)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Splitting bucket " + bucket);
split(bucket.getRangeBegin());
//testAudit(this, _log);
}
return true;
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Peer " + peer + " NOT added to bucket " + bucket);
return false;
}
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Failed to add, probably us: " + peer);
return false;
}
}
/**
* No lock required.
* FIXME will split the closest buckets too far if B > 1 and K < 2**B
* Won't ever really happen and if it does it still works.
*/
private boolean shouldSplit(KBucket b) {
return
b.getRangeBegin() != b.getRangeEnd() &&
b.getKeyCount() > BUCKET_SIZE;
}
/**
* Grabs the write lock.
* Caller must NOT have the read lock.
* The bucket should be splittable (range start != range end).
* @param r the range start of the bucket to be split
*/
private void split(int r) {
if (!getWriteLock())
return;
try {
locked_split(r);
} finally { releaseWriteLock(); }
}
/**
* Creates two or more new buckets. The old bucket is replaced and discarded.
*
* Caller must hold write lock
* The bucket should be splittable (range start != range end).
* @param r the range start of the bucket to be split
*/
private void locked_split(int r) {
int b = pickBucket(r);
while (shouldSplit(_buckets.get(b))) {
KBucket<T> b0 = _buckets.get(b);
// Each bucket gets half the keyspace.
// When B_VALUE = 1, or the bucket is larger than B_FACTOR, then
// e.g. 0-159 => 0-158, 159-159
// When B_VALUE > 1, and the bucket is smaller than B_FACTOR, then
// e.g. 1020-1023 => 1020-1021, 1022-1023
int s1, e1, s2, e2;
s1 = b0.getRangeBegin();
e2 = b0.getRangeEnd();
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.
// Log split
s2 = e2 + 1 - B_FACTOR;
} else {
// The bucket is the smallest "whole" kbucket with a range == B_FACTOR,
// or B_VALUE > 1 and the bucket has already been split.
// Start or continue splitting down to a depth B_VALUE.
// Linear split
s2 = s1 + ((1 + e2 - s1) / 2);
}
e1 = s2 - 1;
if (_log.shouldLog(Log.INFO))
_log.info("Splitting (" + s1 + ',' + e2 + ") -> (" + s1 + ',' + e1 + ") (" + s2 + ',' + e2 + ')');
KBucket<T> b1 = createBucket(s1, e1);
KBucket<T> b2 = createBucket(s2, e2);
for (T key : b0.getEntries()) {
if (getRange(key) < s2)
b1.add(key);
else
b2.add(key);
}
_buckets.set(b, b1);
_buckets.add(b + 1, b2);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Split bucket at idx " + b +
":\n" + b0 +
"\ninto: " + b1 +
"\nand: " + b2);
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("State is now: " + toString());
if (b2.getKeyCount() > BUCKET_SIZE) {
// should be rare... too hard to call _trimmer from here
// (and definitely not from inside the write lock)
if (_log.shouldLog(Log.INFO))
_log.info("All went into 2nd bucket after split");
}
// loop if all the entries went in the first bucket
}
}
/**
* The current number of entries.
*/
public int size() {
int rv = 0;
getReadLock();
try {
for (KBucket b : _buckets) {
rv += b.getKeyCount();
}
} finally { releaseReadLock(); }
return rv;
}
public boolean remove(T entry) {
KBucket kbucket;
getReadLock();
try {
kbucket = getBucket(entry);
} finally { releaseReadLock(); }
boolean removed = kbucket.remove(entry);
return removed;
}
/** @since 0.8.8 */
public void clear() {
getReadLock();
try {
for (KBucket b : _buckets) {
b.clear();
}
} finally { releaseReadLock(); }
_rangeCalc.clear();
}
/**
* @return a copy in a new set
*/
public Set<T> getAll() {
Set<T> all = new HashSet(256);
getReadLock();
try {
for (KBucket b : _buckets) {
all.addAll(b.getEntries());
}
} finally { releaseReadLock(); }
return all;
}
/**
* @return a copy in a new set
*/
public Set<T> getAll(Set<T> toIgnore) {
Set<T> all = getAll();
all.removeAll(toIgnore);
return all;
}
public void getAll(SelectionCollector<T> collector) {
getReadLock();
try {
for (KBucket b : _buckets) {
b.getEntries(collector);
}
} finally { releaseReadLock(); }
}
/**
* The keys closest to us.
* Returned list will never contain us.
* @return non-null, closest first
*/
public List<T> getClosest(int max) {
return getClosest(max, Collections.EMPTY_SET);
}
/**
* The keys closest to us.
* Returned list will never contain us.
* @return non-null, closest first
*/
public List<T> getClosest(int max, Collection<T> toIgnore) {
List<T> rv = new ArrayList(max);
int count = 0;
getReadLock();
try {
// start at first (closest) bucket
for (int i = 0; i < _buckets.size() && count < max; i++) {
Set<T> entries = _buckets.get(i).getEntries();
// add the whole bucket except for ignores,
// extras will be trimmed after sorting
for (T e : entries) {
if (!toIgnore.contains(e)) {
rv.add(e);
count++;
}
}
}
} finally { releaseReadLock(); }
Comparator comp = new XORComparator(_us);
Collections.sort(rv, comp);
int sz = rv.size();
for (int i = sz - 1; i >= max; i--) {
rv.remove(i);
}
return rv;
}
/**
* The keys closest to the key.
* Returned list will never contain us.
* @return non-null, closest first
*/
public List<T> getClosest(T key, int max) {
return getClosest(key, max, Collections.EMPTY_SET);
}
/**
* The keys closest to the key.
* Returned list will never contain us.
* @return non-null, closest first
*/
public List<T> getClosest(T key, int max, Collection<T> toIgnore) {
if (key.equals(_us))
return getClosest(max, toIgnore);
List<T> rv = new ArrayList(max);
int count = 0;
getReadLock();
try {
int start = pickBucket(key);
// start at closest bucket, then to the smaller (closer to us) buckets
for (int i = start; i >= 0 && count < max; i--) {
Set<T> entries = _buckets.get(i).getEntries();
for (T e : entries) {
if (!toIgnore.contains(e)) {
rv.add(e);
count++;
}
}
}
// then the farther from us buckets if necessary
for (int i = start + 1; i < _buckets.size() && count < max; i++) {
Set<T> entries = _buckets.get(i).getEntries();
for (T e : entries) {
if (!toIgnore.contains(e)) {
rv.add(e);
count++;
}
}
}
} finally { releaseReadLock(); }
Comparator comp = new XORComparator(key);
Collections.sort(rv, comp);
int sz = rv.size();
for (int i = sz - 1; i >= max; i--) {
rv.remove(i);
}
return rv;
}
/**
* The bucket number (NOT the range number) that the xor of the key goes in
* Caller must hold read lock
* @return 0 to max-1 or -1 for us
*/
private int pickBucket(T key) {
int range = getRange(key);
if (range < 0)
return -1;
int rv = pickBucket(range);
if (rv >= 0) {
return rv;
}
_log.error("Key does not fit in any bucket?! WTF!\nKey : ["
+ DataHelper.toHexString(key.getData()) + "]"
+ "\nUs : " + _us
+ "\nDelta: ["
+ DataHelper.toHexString(DataHelper.xor(_us.getData(), key.getData()))
+ "]", new Exception("WTF"));
_log.error(toString());
throw new IllegalStateException("pickBucket returned " + rv);
//return -1;
}
/**
* Returned list is a copy of the bucket list, closest first,
* with the actual buckets (not a copy).
*
* Primarily for testing. You shouldn't ever need to get all the buckets.
* Use getClosest() or getAll() instead to get the keys.
*
* @return non-null
*/
List<KBucket<T>> getBuckets() {
getReadLock();
try {
return new ArrayList(_buckets);
} finally { releaseReadLock(); }
}
/**
* The bucket that the xor of the key goes in
* Caller must hold read lock
* @return null if key is us
*/
private KBucket getBucket(T key) {
int bucket = pickBucket(key);
if (bucket < 0)
return null;
return _buckets.get(bucket);
}
/**
* The bucket number that contains this range number
* Caller must hold read lock or write lock
* @return 0 to max-1 or -1 for us
*/
private int pickBucket(int range) {
// If B is small, a linear search from back to front
// is most efficient since most of the keys are at the end...
// If B is larger, there's a lot of sub-buckets
// of equal size to be checked so a binary search is better
if (B_VALUE <= 3) {
for (int i = _buckets.size() - 1; i >= 0; i--) {
KBucket b = _buckets.get(i);
if (range >= b.getRangeBegin() && range <= b.getRangeEnd())
return i;
}
return -1;
} else {
KBucket dummy = new DummyBucket(range);
return Collections.binarySearch(_buckets, dummy, new BucketComparator());
}
}
private List<KBucket> createBuckets() {
// just an initial size
List<KBucket> buckets = new ArrayList(4 * B_FACTOR);
buckets.add(createBucket(0, NUM_BUCKETS -1));
return buckets;
}
private KBucket createBucket(int start, int end) {
if (end - start >= B_FACTOR &&
(((end + 1) & B_FACTOR - 1) != 0 ||
(start & B_FACTOR - 1) != 0))
throw new IllegalArgumentException("Sub-bkt crosses K-bkt boundary: " + start + '-' + end);
KBucket bucket = new KBucketImpl(_context, start, end, BUCKET_SIZE, _trimmer);
return bucket;
}
/**
* The number of bits minus 1 (range number) for the xor of the key.
* Package private for testing only. Others shouldn't need this.
* @return 0 to max-1 or -1 for us
*/
int getRange(T key) {
return _rangeCalc.getRange(key);
}
/**
* 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
*/
public List<T> getExploreKeys(long age) {
List<T> rv = new ArrayList(_buckets.size());
long old = _context.clock().now() - age;
getReadLock();
try {
for (KBucket b : _buckets) {
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(); }
return rv;
}
/**
* Generate a random key to go within this bucket
* Package private for testing only. Others shouldn't need this.
*/
T generateRandomKey(KBucket bucket) {
int begin = bucket.getRangeBegin();
int end = bucket.getRangeEnd();
// number of fixed bits, out of B_VALUE - 1 bits
int fixed = 0;
int bsz = 1 + end - begin;
// compute fixed = B_VALUE - log2(bsz)
// e.g for B=4, B_FACTOR=8, sz 4-> fixed 1, sz 2->fixed 2, sz 1 -> fixed 3
while (bsz < B_FACTOR) {
fixed++;
bsz <<= 1;
}
int fixedBits = 0;
if (fixed > 0) {
// 0x01, 03, 07, 0f, ...
int mask = (1 << fixed) - 1;
// fixed bits masked from begin
fixedBits = (begin >> (B_VALUE - (fixed + 1))) & mask;
}
int obegin = begin;
int oend = end;
begin >>= (B_VALUE - 1);
end >>= (B_VALUE - 1);
// we need randomness for [0, begin) bits
BigInteger variance;
// 00000000rrrr
if (begin > 0)
variance = new BigInteger(begin - fixed, _context.random());
else
variance = BigInteger.ZERO;
// we need nonzero randomness for [begin, end] bits
int numNonZero = 1 + end - begin;
if (numNonZero == 1) {
// 00001000rrrr
variance = variance.setBit(begin);
// fixed bits as the 'main' bucket is split
// 00001fffrrrr
if (fixed > 0)
variance = variance.or(BigInteger.valueOf(fixedBits).shiftLeft(begin - fixed));
} else {
// dont span main bucket boundaries with depth > 1
if (fixed > 0)
throw new IllegalStateException("WTF " + bucket);
BigInteger nonz;
if (numNonZero <= 62) {
// add one to ensure nonzero
long nz = 1 + _context.random().nextLong((1l << numNonZero) - 1);
nonz = BigInteger.valueOf(nz);
} else {
// loop to ensure nonzero
do {
nonz = new BigInteger(numNonZero, _context.random());
} while (nonz.equals(BigInteger.ZERO));
}
// shift left and or-in the nonzero randomness
if (begin > 0)
nonz = nonz.shiftLeft(begin);
// 0000nnnnrrrr
variance = variance.or(nonz);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("SB(" + obegin + ',' + oend + ") KB(" + begin + ',' + end + ") fixed=" + fixed + " fixedBits=" + fixedBits + " numNonZ=" + numNonZero);
byte data[] = variance.toByteArray();
T key = makeKey(data);
byte[] hash = DataHelper.xor(key.getData(), _us.getData());
T rv = makeKey(hash);
// DEBUG
//int range = getRange(rv);
//if (range < obegin || range > oend) {
// throw new IllegalStateException("Generate random key failed range=" + range + " for " + rv + " meant for bucket " + bucket);
//}
return rv;
}
/**
* Make a new SimpleDataStrucure from the data
* @param data size <= SDS length, else throws IAE
* Can be 1 bigger if top byte is zero
*/
private T makeKey(byte[] data) {
int len = _us.length();
int dlen = data.length;
if (dlen > len + 1 ||
(dlen == len + 1 && data[0] != 0))
throw new IllegalArgumentException("bad length " + dlen + " > " + len);
T rv;
try {
rv = (T) _us.getClass().newInstance();
} catch (Exception e) {
_log.error("fail", e);
throw new RuntimeException(e);
}
if (dlen == len) {
rv.setData(data);
} else {
byte[] ndata = new byte[len];
if (dlen == len + 1) {
// one bigger
System.arraycopy(data, 1, ndata, 0, len);
} else {
// smaller
System.arraycopy(data, 0, ndata, len - dlen, dlen);
}
rv.setData(ndata);
}
return rv;
}
private static class Range<T extends SimpleDataStructure> {
private final int _bValue;
private final BigInteger _bigUs;
private final Map<T, Integer> _distanceCache;
public Range(T us, int bValue) {
_bValue = bValue;
_bigUs = new BigInteger(1, us.getData());
_distanceCache = new LHMCache(256);
}
/** @return 0 to max-1 or -1 for us */
public int getRange(T key) {
Integer rv;
synchronized (_distanceCache) {
rv = _distanceCache.get(key);
if (rv == null) {
// easy way when _bValue == 1
//rv = Integer.valueOf(_bigUs.xor(new BigInteger(1, key.getData())).bitLength() - 1);
BigInteger xor = _bigUs.xor(new BigInteger(1, key.getData()));
int range = xor.bitLength() - 1;
if (_bValue > 1) {
int toShift = range + 1 - _bValue;
int highbit = range;
range <<= _bValue - 1;
if (toShift >= 0) {
int extra = xor.clearBit(highbit).shiftRight(toShift).intValue();
range += extra;
//Log log = I2PAppContext.getGlobalContext().logManager().getLog(KBucketSet.class);
//if (log.shouldLog(Log.DEBUG))
// log.debug("highbit " + highbit + " toshift " + toShift + " extra " + extra + " new " + range);
}
}
rv = Integer.valueOf(range);
_distanceCache.put(key, rv);
}
}
return rv.intValue();
}
public void clear() {
synchronized (_distanceCache) {
_distanceCache.clear();
}
}
}
/**
* For Collections.binarySearch.
* getRangeBegin == getRangeEnd.
*/
private static class DummyBucket<T extends SimpleDataStructure> implements KBucket<T> {
private final int r;
public DummyBucket(int range) {
r = range;
}
public int getRangeBegin() { return r; }
public int getRangeEnd() { return r; }
public int getKeyCount() {
return 0;
}
public Set<T> getEntries() {
throw new UnsupportedOperationException();
}
public void getEntries(SelectionCollector<T> collector) {
throw new UnsupportedOperationException();
}
public void clear() {}
public boolean add(T peer) {
throw new UnsupportedOperationException();
}
public boolean remove(T peer) {
return false;
}
public void setLastChanged() {}
public long getLastChanged() {
return 0;
}
}
/**
* For Collections.binarySearch.
* Returns equal for any overlap.
*/
private static class BucketComparator implements Comparator<KBucket> {
public int compare(KBucket l, KBucket r) {
if (l.getRangeEnd() < r.getRangeBegin())
return -1;
if (l.getRangeBegin() > r.getRangeEnd())
return 1;
return 0;
}
}
@Override
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(" with ").append(size())
.append(" keys in ").append(_buckets.size()).append(" buckets:\n");
getReadLock();
try {
int len = _buckets.size();
for (int i = 0; i < len; i++) {
KBucket b = _buckets.get(i);
buf.append("* Bucket ").append(i).append("/").append(len).append(": ");
buf.append(b.toString()).append("\n");
}
} finally { releaseReadLock(); }
return buf.toString();
}
}

View File

@@ -0,0 +1,20 @@
package net.i2p.kademlia;
import net.i2p.data.SimpleDataStructure;
/**
* Called when a kbucket can no longer be split and is too big
* @since 0.9.2
*/
public interface KBucketTrimmer<K extends SimpleDataStructure> {
/**
* Called from add() just before adding the entry.
* You may call getEntries() and/or remove() from here.
* Do NOT call add().
* To always discard a newer entry, always return false.
*
* @param kbucket the kbucket that is now too big
* @return true to actually add the entry.
*/
public boolean trim(KBucket<K> kbucket, K toAdd);
}

View File

@@ -0,0 +1,21 @@
package net.i2p.kademlia;
import net.i2p.I2PAppContext;
import net.i2p.data.SimpleDataStructure;
/**
* Removes a random element, but only if the bucket hasn't changed in 5 minutes.
* @since 0.9.2
*/
public class RandomIfOldTrimmer<T extends SimpleDataStructure> extends RandomTrimmer<T> {
public RandomIfOldTrimmer(I2PAppContext ctx, int max) {
super(ctx, max);
}
public boolean trim(KBucket<T> kbucket, T toAdd) {
if (kbucket.getLastChanged() > _ctx.clock().now() - 5*60*1000)
return false;
return super.trim(kbucket, toAdd);
}
}

View File

@@ -0,0 +1,31 @@
package net.i2p.kademlia;
import java.util.ArrayList;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.data.SimpleDataStructure;
/**
* Removes a random element. Not resistant to flooding.
* @since 0.9.2
*/
public class RandomTrimmer<T extends SimpleDataStructure> implements KBucketTrimmer<T> {
protected final I2PAppContext _ctx;
private final int _max;
public RandomTrimmer(I2PAppContext ctx, int max) {
_ctx = ctx;
_max = max;
}
public boolean trim(KBucket<T> kbucket, T toAdd) {
List<T> e = new ArrayList(kbucket.getEntries());
int sz = e.size();
// concurrency
if (sz < _max)
return true;
T toRemove = e.get(_ctx.random().nextInt(sz));
return kbucket.remove(toRemove);
}
}

View File

@@ -0,0 +1,13 @@
package net.i2p.kademlia;
import net.i2p.data.SimpleDataStructure;
/**
* Removes nothing and always rejects the add. Flood resistant..
* @since 0.9.2
*/
public class RejectTrimmer<T extends SimpleDataStructure> implements KBucketTrimmer<T> {
public boolean trim(KBucket<T> kbucket, T toAdd) {
return false;
}
}

View File

@@ -0,0 +1,11 @@
package net.i2p.kademlia;
import net.i2p.data.SimpleDataStructure;
/**
* Visit kbuckets, gathering matches
* @since 0.9.2
*/
public interface SelectionCollector<T extends SimpleDataStructure> {
public void add(T entry);
}

View File

@@ -0,0 +1,28 @@
package net.i2p.kademlia;
import java.util.Comparator;
import net.i2p.data.DataHelper;
import net.i2p.data.SimpleDataStructure;
/**
* Help sort Hashes in relation to a base key using the XOR metric
*
* @since 0.9.2
*/
class XORComparator<T extends SimpleDataStructure> implements Comparator<T> {
private final byte[] _base;
/**
* @param target key to compare distances with
*/
public XORComparator(T target) {
_base = target.getData();
}
public int compare(T lhs, T rhs) {
byte lhsDelta[] = DataHelper.xor(lhs.getData(), _base);
byte rhsDelta[] = DataHelper.xor(rhs.getData(), _base);
return DataHelper.compareTo(lhsDelta, rhsDelta);
}
}

View File

@@ -0,0 +1,6 @@
<html><body><p>
This is a major rewrite of KBucket, KBucketSet, and KBucketImpl from net.i2p.router.networkdb.kademlia.
The classes are now generic to support SHA1. SHA256, or other key lengths.
The long-term goal is to prove out this new implementation in i2psnark,
then move it to core, then convert the network database to use it.
</p></body></html>

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

@@ -29,8 +29,12 @@ import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.data.Hash;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.ObjectCounter;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer;
/**
* Accepts connections on a TCP port and routes them to sub-acceptors.
@@ -41,11 +45,15 @@ public class ConnectionAcceptor implements Runnable
private I2PServerSocket serverSocket;
private PeerAcceptor peeracceptor;
private Thread thread;
private I2PSnarkUtil _util;
private final I2PSnarkUtil _util;
private final ObjectCounter<Hash> _badCounter = new ObjectCounter();
private boolean stop;
private boolean socketChanged;
private static final int MAX_BAD = 2;
private static final long BAD_CLEAN_INTERVAL = 30*60*1000;
public ConnectionAcceptor(I2PSnarkUtil util) { _util = util; }
public synchronized void startAccepting(PeerCoordinatorSet set, I2PServerSocket socket) {
@@ -59,6 +67,7 @@ public class ConnectionAcceptor implements Runnable
thread = new I2PAppThread(this, "I2PSnark acceptor");
thread.setDaemon(true);
thread.start();
_util.getContext().simpleScheduler().addPeriodicEvent(new Cleaner(), BAD_CLEAN_INTERVAL);
}
}
}
@@ -70,11 +79,10 @@ public class ConnectionAcceptor implements Runnable
this.peeracceptor = peeracceptor;
_util = util;
socketChanged = false;
stop = false;
thread = new I2PAppThread(this, "I2PSnark acceptor");
thread.setDaemon(true);
thread.start();
_util.getContext().simpleScheduler().addPeriodicEvent(new Cleaner(), BAD_CLEAN_INTERVAL);
}
public void halt()
@@ -138,7 +146,13 @@ public class ConnectionAcceptor implements Runnable
}
} else {
if (socket.getPeerDestination().equals(_util.getMyDestination())) {
_util.debug("Incoming connection from myself", Snark.ERROR);
_log.error("Incoming connection from myself");
try { socket.close(); } catch (IOException ioe) {}
continue;
}
if (_badCounter.count(socket.getPeerDestination().calculateHash()) >= MAX_BAD) {
if (_log.shouldLog(Log.WARN))
_log.warn("Rejecting connection from " + socket.getPeerDestination().calculateHash() + " after " + MAX_BAD + " failures");
try { socket.close(); } catch (IOException ioe) {}
continue;
}
@@ -149,13 +163,13 @@ public class ConnectionAcceptor implements Runnable
catch (I2PException ioe)
{
if (!socketChanged) {
_util.debug("Error while accepting: " + ioe, Snark.ERROR);
_log.error("Error while accepting", ioe);
stop = true;
}
}
catch (IOException ioe)
{
_util.debug("Error while accepting: " + ioe, Snark.ERROR);
_log.error("Error while accepting", ioe);
stop = true;
}
// catch oom?
@@ -171,10 +185,12 @@ public class ConnectionAcceptor implements Runnable
}
private class Handler implements Runnable {
private I2PSocket _socket;
private final I2PSocket _socket;
public Handler(I2PSocket socket) {
_socket = socket;
}
public void run() {
try {
InputStream in = _socket.getInputStream();
@@ -182,13 +198,23 @@ public class ConnectionAcceptor implements Runnable
// this is for the readahead in PeerAcceptor.connection()
in = new BufferedInputStream(in);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Handling socket from " + _socket.getPeerDestination().calculateHash().toBase64());
_log.debug("Handling socket from " + _socket.getPeerDestination().calculateHash());
peeracceptor.connection(_socket, in, out);
} catch (PeerAcceptor.ProtocolException ihe) {
_badCounter.increment(_socket.getPeerDestination().calculateHash());
if (_log.shouldLog(Log.INFO))
_log.info("Protocol error from " + _socket.getPeerDestination().calculateHash(), ihe);
try { _socket.close(); } catch (IOException ignored) { }
} catch (IOException ioe) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Error handling connection from " + _socket.getPeerDestination().calculateHash().toBase64(), ioe);
_log.debug("Error handling connection from " + _socket.getPeerDestination().calculateHash(), ioe);
try { _socket.close(); } catch (IOException ignored) { }
}
}
}
/** @since 0.9.1 */
private class Cleaner implements SimpleTimer.TimedEvent {
public void timeReached() { _badCounter.clear(); }
}
}

View File

@@ -24,7 +24,7 @@ package org.klomp.snark;
/**
* Callback used when some peer changes state.
*/
public interface CoordinatorListener
interface CoordinatorListener
{
/**
* Called when the PeerCoordinator notices a change in the state of a peer.
@@ -40,4 +40,5 @@ public interface CoordinatorListener
public boolean overUploadLimit(int uploaders);
public boolean overUpBWLimit();
public boolean overUpBWLimit(long total);
public void addMessage(String message);
}

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,7 +1,6 @@
package org.klomp.snark;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
@@ -15,7 +14,6 @@ import net.i2p.util.Log;
import org.klomp.snark.bencode.BDecoder;
import org.klomp.snark.bencode.BEncoder;
import org.klomp.snark.bencode.BEValue;
import org.klomp.snark.bencode.InvalidBEncodingException;
/**
* REF: BEP 10 Extension Protocol
@@ -24,14 +22,15 @@ import org.klomp.snark.bencode.InvalidBEncodingException;
*/
abstract class ExtensionHandler {
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ExtensionHandler.class);
public static final int ID_HANDSHAKE = 0;
public static final int ID_METADATA = 1;
public static final String TYPE_METADATA = "ut_metadata";
public static final int ID_PEX = 2;
/** not ut_pex since the compact format is different */
public static final String TYPE_PEX = "i2p_pex";
public static final int ID_DHT = 3;
/** not using the option bit since the compact format is different */
public static final String TYPE_DHT = "i2p_dht";
/** Pieces * SHA1 Hash length, + 25% extra for file names, benconding overhead, etc */
private static final int MAX_METADATA_SIZE = Storage.MAX_PIECES * 20 * 5 / 4;
private static final int PARALLEL_REQUESTS = 3;
@@ -39,15 +38,23 @@ abstract class ExtensionHandler {
/**
* @param metasize -1 if unknown
* @param pexAndMetadata advertise these capabilities
* @param dht advertise DHT capability
* @return bencoded outgoing handshake message
*/
public static byte[] getHandshake(int metasize) {
public static byte[] getHandshake(int metasize, boolean pexAndMetadata, boolean dht) {
Map<String, Object> handshake = new HashMap();
Map<String, Integer> m = new HashMap();
m.put(TYPE_METADATA, Integer.valueOf(ID_METADATA));
m.put(TYPE_PEX, Integer.valueOf(ID_PEX));
if (metasize >= 0)
handshake.put("metadata_size", Integer.valueOf(metasize));
if (pexAndMetadata) {
m.put(TYPE_METADATA, Integer.valueOf(ID_METADATA));
m.put(TYPE_PEX, Integer.valueOf(ID_PEX));
if (metasize >= 0)
handshake.put("metadata_size", Integer.valueOf(metasize));
}
if (dht) {
m.put(TYPE_DHT, Integer.valueOf(ID_DHT));
}
// include the map even if empty so the far-end doesn't NPE
handshake.put("m", m);
handshake.put("p", Integer.valueOf(6881));
handshake.put("v", "I2PSnark");
@@ -56,21 +63,24 @@ abstract class ExtensionHandler {
}
public static void handleMessage(Peer peer, PeerListener listener, int id, byte[] bs) {
if (_log.shouldLog(Log.INFO))
_log.info("Got extension msg " + id + " length " + bs.length + " from " + peer);
Log log = I2PAppContext.getGlobalContext().logManager().getLog(ExtensionHandler.class);
if (log.shouldLog(Log.INFO))
log.info("Got extension msg " + id + " length " + bs.length + " from " + peer);
if (id == ID_HANDSHAKE)
handleHandshake(peer, listener, bs);
handleHandshake(peer, listener, bs, log);
else if (id == ID_METADATA)
handleMetadata(peer, listener, bs);
handleMetadata(peer, listener, bs, log);
else if (id == ID_PEX)
handlePEX(peer, listener, bs);
else if (_log.shouldLog(Log.INFO))
_log.info("Unknown extension msg " + id + " from " + peer);
handlePEX(peer, listener, bs, log);
else if (id == ID_DHT)
handleDHT(peer, listener, bs, log);
else if (log.shouldLog(Log.INFO))
log.info("Unknown extension msg " + id + " from " + peer);
}
private static void handleHandshake(Peer peer, PeerListener listener, byte[] bs) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got handshake msg from " + peer);
private static void handleHandshake(Peer peer, PeerListener listener, byte[] bs, Log log) {
if (log.shouldLog(Log.DEBUG))
log.debug("Got handshake msg from " + peer);
try {
// this throws NPE on missing keys
InputStream is = new ByteArrayInputStream(bs);
@@ -81,20 +91,26 @@ abstract class ExtensionHandler {
Map<String, BEValue> msgmap = map.get("m").getMap();
if (msgmap.get(TYPE_PEX) != null) {
if (_log.shouldLog(Log.WARN))
_log.debug("Peer supports PEX extension: " + peer);
if (log.shouldLog(Log.DEBUG))
log.debug("Peer supports PEX extension: " + peer);
// peer state calls peer listener calls sendPEX()
}
if (msgmap.get(TYPE_DHT) != null) {
if (log.shouldLog(Log.DEBUG))
log.debug("Peer supports DHT extension: " + peer);
// peer state calls peer listener calls sendDHT()
}
MagnetState state = peer.getMagnetState();
if (msgmap.get(TYPE_METADATA) == null) {
if (_log.shouldLog(Log.WARN))
_log.debug("Peer does not support metadata extension: " + peer);
if (log.shouldLog(Log.DEBUG))
log.debug("Peer does not support metadata extension: " + peer);
// drop if we need metainfo and we haven't found anybody yet
synchronized(state) {
if (!state.isInitialized()) {
_log.debug("Dropping peer, we need metadata! " + peer);
log.debug("Dropping peer, we need metadata! " + peer);
peer.disconnect();
}
}
@@ -103,20 +119,20 @@ abstract class ExtensionHandler {
BEValue msize = map.get("metadata_size");
if (msize == null) {
if (_log.shouldLog(Log.WARN))
_log.debug("Peer does not have the metainfo size yet: " + peer);
if (log.shouldLog(Log.DEBUG))
log.debug("Peer does not have the metainfo size yet: " + peer);
// drop if we need metainfo and we haven't found anybody yet
synchronized(state) {
if (!state.isInitialized()) {
_log.debug("Dropping peer, we need metadata! " + peer);
log.debug("Dropping peer, we need metadata! " + peer);
peer.disconnect();
}
}
return;
}
int metaSize = msize.getInt();
if (_log.shouldLog(Log.WARN))
_log.debug("Got the metainfo size: " + metaSize);
if (log.shouldLog(Log.DEBUG))
log.debug("Got the metainfo size: " + metaSize);
int remaining;
synchronized(state) {
@@ -125,21 +141,21 @@ abstract class ExtensionHandler {
if (state.isInitialized()) {
if (state.getSize() != metaSize) {
if (_log.shouldLog(Log.WARN))
_log.debug("Wrong metainfo size " + metaSize + " from: " + peer);
if (log.shouldLog(Log.DEBUG))
log.debug("Wrong metainfo size " + metaSize + " from: " + peer);
peer.disconnect();
return;
}
} else {
// initialize it
if (metaSize > MAX_METADATA_SIZE) {
if (_log.shouldLog(Log.WARN))
_log.debug("Huge metainfo size " + metaSize + " from: " + peer);
if (log.shouldLog(Log.DEBUG))
log.debug("Huge metainfo size " + metaSize + " from: " + peer);
peer.disconnect(false);
return;
}
if (_log.shouldLog(Log.INFO))
_log.info("Initialized state, metadata size = " + metaSize + " from " + peer);
if (log.shouldLog(Log.INFO))
log.info("Initialized state, metadata size = " + metaSize + " from " + peer);
state.initialize(metaSize);
}
remaining = state.chunksRemaining();
@@ -152,13 +168,13 @@ abstract class ExtensionHandler {
synchronized(state) {
chk = state.getNextRequest();
}
if (_log.shouldLog(Log.INFO))
_log.info("Request chunk " + chk + " from " + peer);
if (log.shouldLog(Log.INFO))
log.info("Request chunk " + chk + " from " + peer);
sendRequest(peer, chk);
}
} catch (Exception e) {
if (_log.shouldLog(Log.WARN))
_log.warn("Handshake exception from " + peer, e);
if (log.shouldLog(Log.WARN))
log.warn("Handshake exception from " + peer, e);
}
}
@@ -166,15 +182,13 @@ abstract class ExtensionHandler {
private static final int TYPE_DATA = 1;
private static final int TYPE_REJECT = 2;
private static final int CHUNK_SIZE = 16*1024;
/**
* REF: BEP 9
* @since 0.8.4
*/
private static void handleMetadata(Peer peer, PeerListener listener, byte[] bs) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got metadata msg from " + peer);
private static void handleMetadata(Peer peer, PeerListener listener, byte[] bs, Log log) {
if (log.shouldLog(Log.DEBUG))
log.debug("Got metadata msg from " + peer);
try {
InputStream is = new ByteArrayInputStream(bs);
BDecoder dec = new BDecoder(is);
@@ -185,8 +199,8 @@ abstract class ExtensionHandler {
MagnetState state = peer.getMagnetState();
if (type == TYPE_REQUEST) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got request for " + piece + " from: " + peer);
if (log.shouldLog(Log.DEBUG))
log.debug("Got request for " + piece + " from: " + peer);
byte[] pc;
synchronized(state) {
pc = state.getChunk(piece);
@@ -197,8 +211,8 @@ abstract class ExtensionHandler {
listener.uploaded(peer, pc.length);
} else if (type == TYPE_DATA) {
int size = map.get("total_size").getInt();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got data for " + piece + " length " + size + " from: " + peer);
if (log.shouldLog(Log.DEBUG))
log.debug("Got data for " + piece + " length " + size + " from: " + peer);
boolean done;
int chk = -1;
synchronized(state) {
@@ -207,14 +221,14 @@ abstract class ExtensionHandler {
int len = is.available();
if (len != size) {
// probably fatal
if (_log.shouldLog(Log.WARN))
_log.warn("total_size " + size + " but avail data " + len);
if (log.shouldLog(Log.WARN))
log.warn("total_size " + size + " but avail data " + len);
}
peer.downloaded(len);
listener.downloaded(peer, len);
done = state.saveChunk(piece, bs, bs.length - len, len);
if (_log.shouldLog(Log.INFO))
_log.info("Got chunk " + piece + " from " + peer);
if (log.shouldLog(Log.INFO))
log.info("Got chunk " + piece + " from " + peer);
if (!done)
chk = state.getNextRequest();
}
@@ -223,26 +237,26 @@ abstract class ExtensionHandler {
// Done!
// PeerState will call the listener (peer coord), who will
// check to see if the MagnetState has it
if (_log.shouldLog(Log.WARN))
_log.warn("Got last chunk from " + peer);
if (log.shouldLog(Log.WARN))
log.warn("Got last chunk from " + peer);
} else {
// get the next chunk
if (_log.shouldLog(Log.INFO))
_log.info("Request chunk " + chk + " from " + peer);
if (log.shouldLog(Log.INFO))
log.info("Request chunk " + chk + " from " + peer);
sendRequest(peer, chk);
}
} else if (type == TYPE_REJECT) {
if (_log.shouldLog(Log.WARN))
_log.warn("Got reject msg from " + peer);
if (log.shouldLog(Log.WARN))
log.warn("Got reject msg from " + peer);
peer.disconnect(false);
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Got unknown metadata msg from " + peer);
if (log.shouldLog(Log.WARN))
log.warn("Got unknown metadata msg from " + peer);
peer.disconnect(false);
}
} catch (Exception e) {
if (_log.shouldLog(Log.WARN))
_log.info("Metadata ext. msg. exception from " + peer, e);
if (log.shouldLog(Log.INFO))
log.info("Metadata ext. msg. exception from " + peer, e);
// fatal ?
peer.disconnect(false);
}
@@ -252,9 +266,11 @@ abstract class ExtensionHandler {
sendMessage(peer, TYPE_REQUEST, piece);
}
/****
private static void sendReject(Peer peer, int piece) {
sendMessage(peer, TYPE_REJECT, piece);
}
****/
/** REQUEST and REJECT are the same except for message type */
private static void sendMessage(Peer peer, int type, int piece) {
@@ -267,8 +283,8 @@ abstract class ExtensionHandler {
peer.sendExtension(hisMsgCode, payload);
} catch (Exception e) {
// NPE, no metadata capability
if (_log.shouldLog(Log.WARN))
_log.info("Metadata send req msg exception to " + peer, e);
//if (log.shouldLog(Log.INFO))
// log.info("Metadata send req msg exception to " + peer, e);
}
}
@@ -286,8 +302,8 @@ abstract class ExtensionHandler {
peer.sendExtension(hisMsgCode, payload);
} catch (Exception e) {
// NPE, no metadata caps
if (_log.shouldLog(Log.WARN))
_log.info("Metadata send piece msg exception to " + peer, e);
//if (log.shouldLog(Log.INFO))
// log.info("Metadata send piece msg exception to " + peer, e);
}
}
@@ -301,15 +317,18 @@ abstract class ExtensionHandler {
* added.f and dropped unsupported
* @since 0.8.4
*/
private static void handlePEX(Peer peer, PeerListener listener, byte[] bs) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got PEX msg from " + peer);
private static void handlePEX(Peer peer, PeerListener listener, byte[] bs, Log log) {
if (log.shouldLog(Log.DEBUG))
log.debug("Got PEX msg from " + peer);
try {
InputStream is = new ByteArrayInputStream(bs);
BDecoder dec = new BDecoder(is);
BEValue bev = dec.bdecodeMap();
Map<String, BEValue> map = bev.getMap();
byte[] ids = map.get("added").getBytes();
bev = map.get("added");
if (bev == null)
return;
byte[] ids = bev.getBytes();
if (ids.length < HASH_LENGTH)
return;
int len = Math.min(ids.length, (I2PSnarkUtil.MAX_CONNECTIONS - 1) * HASH_LENGTH);
@@ -319,14 +338,36 @@ abstract class ExtensionHandler {
System.arraycopy(ids, off, hash, 0, HASH_LENGTH);
if (DataHelper.eq(hash, peer.getPeerID().getDestHash()))
continue;
PeerID pID = new PeerID(hash);
PeerID pID = new PeerID(hash, listener.getUtil());
peers.add(pID);
}
// could include ourselves, listener must remove
listener.gotPeers(peer, peers);
} catch (Exception e) {
if (_log.shouldLog(Log.WARN))
_log.info("PEX msg exception from " + peer, e);
if (log.shouldLog(Log.INFO))
log.info("PEX msg exception from " + peer, e);
//peer.disconnect(false);
}
}
/**
* Receive the DHT port numbers
* @since DHT
*/
private static void handleDHT(Peer peer, PeerListener listener, byte[] bs, Log log) {
if (log.shouldLog(Log.DEBUG))
log.debug("Got DHT msg from " + peer);
try {
InputStream is = new ByteArrayInputStream(bs);
BDecoder dec = new BDecoder(is);
BEValue bev = dec.bdecodeMap();
Map<String, BEValue> map = bev.getMap();
int qport = map.get("port").getInt();
int rport = map.get("rport").getInt();
listener.gotPort(peer, qport, rport);
} catch (Exception e) {
if (log.shouldLog(Log.INFO))
log.info("DHT msg exception from " + peer, e);
//peer.disconnect(false);
}
}
@@ -353,9 +394,27 @@ abstract class ExtensionHandler {
peer.sendExtension(hisMsgCode, payload);
} catch (Exception e) {
// NPE, no PEX caps
if (_log.shouldLog(Log.WARN))
_log.info("PEX msg exception to " + peer, e);
//if (log.shouldLog(Log.INFO))
// log.info("PEX msg exception to " + peer, e);
}
}
/**
* Send the DHT port numbers
* @since DHT
*/
public static void sendDHT(Peer peer, int qport, int rport) {
Map<String, Object> map = new HashMap();
map.put("port", Integer.valueOf(qport));
map.put("rport", Integer.valueOf(rport));
byte[] payload = BEncoder.bencode(map);
try {
int hisMsgCode = peer.getHandshakeMap().get("m").getMap().get(TYPE_DHT).getInt();
peer.sendExtension(hisMsgCode, payload);
} catch (Exception e) {
// NPE, no DHT caps
//if (log.shouldLog(Log.INFO))
// log.info("DHT msg exception to " + peer, e);
}
}
}

View File

@@ -1,8 +1,10 @@
package org.klomp.snark;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -20,6 +22,7 @@ import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketEepGet;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManagerFactory;
import net.i2p.client.streaming.I2PSocketOptions;
import net.i2p.data.Base32;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
@@ -35,7 +38,7 @@ import net.i2p.util.SimpleTimer;
import net.i2p.util.Translate;
import org.klomp.snark.dht.DHT;
//import org.klomp.snark.dht.KRPC;
import org.klomp.snark.dht.KRPC;
/**
* I2P specific helpers for I2PSnark
@@ -53,26 +56,30 @@ public class I2PSnarkUtil {
private String _i2cpHost;
private int _i2cpPort;
private final Map<String, String> _opts;
private I2PSocketManager _manager;
private volatile I2PSocketManager _manager;
private boolean _configured;
private final Set<Hash> _shitlist;
private volatile boolean _connecting;
private final Set<Hash> _banlist;
private int _maxUploaders;
private int _maxUpBW;
private int _maxConnections;
private final File _tmpDir;
private int _startupDelay;
private boolean _shouldUseOT;
private boolean _shouldUseDHT;
private boolean _areFilesPublic;
private String _openTrackerString;
private List<String> _openTrackers;
private DHT _dht;
private static final int EEPGET_CONNECT_TIMEOUT = 45*1000;
private static final int EEPGET_CONNECT_TIMEOUT_SHORT = 5*1000;
public static final int DEFAULT_STARTUP_DELAY = 3;
public static final boolean DEFAULT_USE_OPENTRACKERS = true;
public static final String DEFAULT_OPENTRACKERS = "http://tracker.welterde.i2p/a";
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";
//private static final boolean ENABLE_DHT = true;
public static final boolean DEFAULT_USE_DHT = true;
public I2PSnarkUtil(I2PAppContext ctx) {
_context = ctx;
@@ -80,13 +87,15 @@ public class I2PSnarkUtil {
_opts = new HashMap();
//setProxy("127.0.0.1", 4444);
setI2CPConfig("127.0.0.1", 7654, null);
_shitlist = new ConcurrentHashSet();
_configured = false;
_banlist = new ConcurrentHashSet();
_maxUploaders = Snark.MAX_TOTAL_UPLOADERS;
_maxUpBW = DEFAULT_MAX_UP_BW;
_maxConnections = MAX_CONNECTIONS;
_startupDelay = DEFAULT_STARTUP_DELAY;
_shouldUseOT = DEFAULT_USE_OPENTRACKERS;
// FIXME split if default has more than one
_openTrackers = Collections.singletonList(DEFAULT_OPENTRACKERS);
_shouldUseDHT = DEFAULT_USE_DHT;
// 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
@@ -115,6 +124,9 @@ public class I2PSnarkUtil {
}
******/
/** @since 0.9.1 */
public I2PAppContext getContext() { return _context; }
public boolean configured() { return _configured; }
public void setI2CPConfig(String i2cpHost, int i2cpPort, Map opts) {
@@ -184,11 +196,15 @@ public class I2PSnarkUtil {
/** @since 0.8.9 */
public void setFilesPublic(boolean yes) { _areFilesPublic = yes; }
/** @since 0.9.1 */
public File getTempDir() { return _tmpDir; }
/**
* Connect to the router, if we aren't already
*/
synchronized public boolean connect() {
if (_manager == null) {
_connecting = true;
// try to find why reconnecting after stop
if (_log.shouldLog(Log.DEBUG))
_log.debug("Connecting to I2P", new Exception("I did it"));
@@ -203,10 +219,14 @@ public class I2PSnarkUtil {
opts.setProperty("inbound.nickname", "I2PSnark");
if (opts.getProperty("outbound.nickname") == null)
opts.setProperty("outbound.nickname", "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)
// opts.setProperty("i2p.streaming.connectDelay", "500");
if (opts.getProperty(I2PSocketOptions.PROP_CONNECT_TIMEOUT) == null)
opts.setProperty(I2PSocketOptions.PROP_CONNECT_TIMEOUT, "75000");
if (opts.getProperty("i2p.streaming.inactivityTimeout") == null)
opts.setProperty("i2p.streaming.inactivityTimeout", "240000");
if (opts.getProperty("i2p.streaming.inactivityAction") == null)
@@ -219,11 +239,21 @@ public class I2PSnarkUtil {
// opts.setProperty("i2p.streaming.writeTimeout", "90000");
//if (opts.getProperty("i2p.streaming.readTimeout") == null)
// opts.setProperty("i2p.streaming.readTimeout", "120000");
if (opts.getProperty("i2p.streaming.maxConnsPerMinute") == null)
opts.setProperty("i2p.streaming.maxConnsPerMinute", "2");
if (opts.getProperty("i2p.streaming.maxTotalConnsPerMinute") == null)
opts.setProperty("i2p.streaming.maxTotalConnsPerMinute", "8");
if (opts.getProperty("i2p.streaming.maxConnsPerHour") == null)
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;
}
// FIXME this only instantiates krpc once, left stuck with old manager
//if (ENABLE_DHT && _manager != null && _dht == null)
// _dht = new KRPC(_context, _manager.getSession());
if (_shouldUseDHT && _manager != null && _dht == null)
_dht = new KRPC(_context, _manager.getSession());
return (_manager != null);
}
@@ -235,15 +265,35 @@ public class I2PSnarkUtil {
public boolean connected() { return _manager != null; }
/** @since 0.9.1 */
public boolean isConnecting() { return _manager == null && _connecting; }
/**
* For FetchAndAdd
* @return null if not connected
* @since 0.9.1
*/
public I2PSocketManager getSocketManager() {
return _manager;
}
/**
* Destroy the destination itself
*/
public void disconnect() {
public synchronized void disconnect() {
if (_dht != null) {
_dht.stop();
_dht = null;
}
I2PSocketManager mgr = _manager;
// FIXME this can cause race NPEs elsewhere
_manager = null;
_shitlist.clear();
mgr.destroySocketManager();
_banlist.clear();
if (mgr != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Disconnecting from I2P", new Exception("I did it"));
mgr.destroySocketManager();
}
// this will delete a .torrent file d/l in progress so don't do that...
FileUtil.rmdir(_tmpDir, false);
// in case the user will d/l a .torrent file next...
@@ -261,32 +311,45 @@ 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);
SimpleScheduler.getInstance().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); }
}
/**
* fetch the given URL, returning the file it is stored in, or null on error
* Fetch the given URL, returning the file it is stored in, or null on error.
* No retries.
*/
public File get(String url) { return get(url, true, 0); }
/**
* @param rewrite if true, convert http://KEY.i2p/foo/announce to http://i2p/KEY/foo/announce
*/
public File get(String url, boolean rewrite) { return get(url, rewrite, 0); }
/**
* @param retries if < 0, set timeout to a few seconds
*/
public File get(String url, int retries) { return get(url, true, retries); }
/**
* @param retries if < 0, set timeout to a few seconds
*/
public File get(String url, boolean rewrite, int retries) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy);
@@ -295,7 +358,7 @@ public class I2PSnarkUtil {
// we could use the system tmp dir but deleteOnExit() doesn't seem to work on all platforms...
out = SecureFile.createTempFile("i2psnark", null, _tmpDir);
} catch (IOException ioe) {
ioe.printStackTrace();
_log.error("temp file error", ioe);
if (out != null)
out.delete();
return null;
@@ -307,12 +370,21 @@ public class I2PSnarkUtil {
//_log.debug("Rewritten url [" + fetchURL + "]");
//EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, retries, out.getAbsolutePath(), fetchURL);
// Use our tunnel for announces and .torrent fetches too! Make sure we're connected first...
if (!connected()) {
if (!connect())
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;
}
}
EepGet get = new I2PSocketEepGet(_context, _manager, retries, out.getAbsolutePath(), fetchURL);
if (get.fetch()) {
if (get.fetch(timeout)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
return out;
@@ -324,6 +396,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)
@@ -386,7 +498,8 @@ public class I2PSnarkUtil {
if (sess != null) {
byte[] b = Base32.decode(ip.substring(0, BASE32_HASH_LENGTH));
if (b != null) {
Hash h = new Hash(b);
//Hash h = new Hash(b);
Hash h = Hash.create(b);
if (_log.shouldLog(Log.INFO))
_log.info("Using existing session for lookup of " + ip);
try {
@@ -441,30 +554,26 @@ public class I2PSnarkUtil {
}
/** @param ot non-null */
public void setOpenTrackerString(String ot) {
_openTrackerString = ot;
public void setOpenTrackers(List<String> ot) {
_openTrackers = ot;
}
public String getOpenTrackerString() {
if (_openTrackerString == null)
return DEFAULT_OPENTRACKERS;
return _openTrackerString;
}
/** comma delimited list open trackers to use as backups */
/** sorted map of name to announceURL=baseURL */
/** List of open trackers to use as backups
* @return non-null, possibly unmodifiable, empty if disabled
*/
public List<String> getOpenTrackers() {
if (!shouldUseOpenTrackers())
return null;
List<String> rv = new ArrayList(1);
String trackers = getOpenTrackerString();
StringTokenizer tok = new StringTokenizer(trackers, ", ");
while (tok.hasMoreTokens())
rv.add(tok.nextToken());
if (rv.isEmpty())
return null;
return rv;
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) {
@@ -474,6 +583,22 @@ public class I2PSnarkUtil {
public boolean shouldUseOpenTrackers() {
return _shouldUseOT;
}
/** @since DHT */
public synchronized void setUseDHT(boolean yes) {
_shouldUseDHT = yes;
if (yes && _manager != null && _dht == null) {
_dht = new KRPC(_context, _manager.getSession());
} else if (!yes && _dht != null) {
_dht.stop();
_dht = null;
}
}
/** @since DHT */
public boolean shouldUseDHT() {
return _shouldUseDHT;
}
/**
* Like DataHelper.toHexString but ensures no loss of leading zero bytes
@@ -490,40 +615,6 @@ public class I2PSnarkUtil {
return buf.toString();
}
/** hook between snark's logger and an i2p log */
void debug(String msg, int snarkDebugLevel) {
debug(msg, snarkDebugLevel, null);
}
void debug(String msg, int snarkDebugLevel, Throwable t) {
if (t instanceof OutOfMemoryError) {
try { Thread.sleep(100); } catch (InterruptedException ie) {}
try {
t.printStackTrace();
} catch (Throwable tt) {}
try {
System.out.println("OOM thread: " + Thread.currentThread().getName());
} catch (Throwable tt) {}
}
switch (snarkDebugLevel) {
case 0:
case 1:
_log.error(msg, t);
break;
case 2:
_log.warn(msg, t);
break;
case 3:
case 4:
_log.info(msg, t);
break;
case 5:
case 6:
default:
_log.debug(msg, t);
break;
}
}
private static final String BUNDLE_NAME = "org.klomp.snark.web.messages";
/** lang in routerconsole.lang property, else current locale */

View File

@@ -5,10 +5,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.RandomSource;
import org.klomp.snark.bencode.BDecoder;
import org.klomp.snark.bencode.BEValue;
@@ -27,7 +27,6 @@ import org.klomp.snark.bencode.BEValue;
*/
class MagnetState {
public static final int CHUNK_SIZE = 16*1024;
private static final Random random = I2PAppContext.getGlobalContext().random();
private final byte[] infohash;
private boolean complete;
@@ -129,7 +128,7 @@ class MagnetState {
throw new IllegalArgumentException("not initialized");
if (complete)
throw new IllegalArgumentException("complete");
int rand = random.nextInt(totalChunks);
int rand = RandomSource.getInstance().nextInt(totalChunks);
for (int i = 0; i < totalChunks; i++) {
int chk = (i + rand) % totalChunks;
if (!(have.get(chk) || requested.get(chk))) {

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,10 +23,13 @@ package org.klomp.snark;
import java.io.DataOutputStream;
import java.io.IOException;
import net.i2p.util.SimpleTimer;
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.
/**
* Used to queue outgoing connections
* sendMessage() should be used to translate them to wire format.
*/
class Message
{
final static byte KEEP_ALIVE = -1;
@@ -71,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
{
@@ -81,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
@@ -141,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

@@ -33,7 +33,6 @@ import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.crypto.SHA1;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
@@ -61,6 +60,7 @@ public class MetaInfo
private final int piece_length;
private final byte[] piece_hashes;
private final long length;
private final boolean privateTorrent;
private Map<String, BEValue> infoMap;
/**
@@ -71,7 +71,7 @@ public class MetaInfo
* @param lengths null for single-file torrent
*/
MetaInfo(String announce, String name, String name_utf8, List<List<String>> files, List<Long> lengths,
int piece_length, byte[] piece_hashes, long length)
int piece_length, byte[] piece_hashes, long length, boolean privateTorrent)
{
this.announce = announce;
this.name = name;
@@ -82,6 +82,7 @@ public class MetaInfo
this.piece_length = piece_length;
this.piece_hashes = piece_hashes;
this.length = length;
this.privateTorrent = privateTorrent;
// TODO if we add a parameter for other keys
//if (other != null) {
@@ -160,6 +161,10 @@ public class MetaInfo
else
name_utf8 = null;
// BEP 27
val = info.get("private");
privateTorrent = val != null && val.getString().equals("1");
val = info.get("piece length");
if (val == null)
throw new InvalidBEncodingException("Missing piece length number");
@@ -212,7 +217,7 @@ public class MetaInfo
if (l < oldTotal)
throw new InvalidBEncodingException("Huge total length");
val = (BEValue)desc.get("path");
val = desc.get("path");
if (val == null)
throw new InvalidBEncodingException("Missing path list");
List<BEValue> path_list = val.getList();
@@ -238,7 +243,7 @@ public class MetaInfo
m_files.add(Collections.unmodifiableList(file));
val = (BEValue)desc.get("path.utf-8");
val = desc.get("path.utf-8");
if (val != null) {
path_list = val.getList();
path_length = path_list.size();
@@ -318,6 +323,14 @@ public class MetaInfo
return name;
}
/**
* Is it a private torrent?
* @since 0.9
*/
public boolean isPrivate() {
return privateTorrent;
}
/**
* Returns a list of lists of file name hierarchies or null if it is
* a single name. It has the same size as the list returned by
@@ -409,6 +422,29 @@ public class MetaInfo
return false;
return true;
}
/**
* @return good
* @since 0.9.1
*/
boolean checkPiece(PartialPiece pp) {
MessageDigest sha1 = SHA1.getInstance();
int piece = pp.getPiece();
byte[] hash;
try {
hash = pp.getHash();
} catch (IOException ioe) {
// Could be caused by closing a peer connnection
// we don't want the exception to propagate through
// to Storage.putPiece()
_log.warn("Error checking", ioe);
return false;
}
for (int i = 0; i < 20; i++)
if (hash[i] != piece_hashes[20 * piece + i])
return false;
return true;
}
/**
* Returns the total length of the torrent in bytes.
@@ -439,7 +475,7 @@ public class MetaInfo
{
return new MetaInfo(announce, name, name_utf8, files,
lengths, piece_length,
piece_hashes, length);
piece_hashes, length, privateTorrent);
}
/**
@@ -475,6 +511,10 @@ public class MetaInfo
info.put("name", name);
if (name_utf8 != null)
info.put("name.utf-8", name_utf8);
// BEP 27
if (privateTorrent)
info.put("private", "1");
info.put("piece length", Integer.valueOf(piece_length));
info.put("pieces", piece_hashes);
if (files == null)

View File

@@ -1,6 +1,24 @@
package org.klomp.snark;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
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;
/**
* Store the received data either on the heap or in a temp file.
* The third option, to write chunks directly to the destination file,
* is unimplemented.
*
* This is the class passed from PeerCoordinator to PeerState so
* PeerState may start requests.
*
@@ -8,45 +26,84 @@ package org.klomp.snark;
* a piece is not completely downloaded, for example
* when the Peer disconnects or chokes.
*
* New objects for the same piece are created during the end game -
* this object should not be shared among multiple peers.
*
* @since 0.8.2
*/
class PartialPiece implements Comparable {
private final int piece;
// we store the piece so we can use it in compareTo()
private final Piece piece;
// null if using temp file
private final byte[] bs;
private final int off;
private final long createdTime;
private int off;
//private final long createdTime;
private File tempfile;
private RandomAccessFile raf;
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
private static int _max_in_mem = MAX_IN_MEM;
/**
* Used by PeerCoordinator.
* Creates a new PartialPiece, with no chunks yet downloaded.
* Allocates the data.
* Allocates the data storage area, either on the heap or in the
* temp directory, depending on size.
*
* @param piece Piece number requested.
* @param len must be equal to the piece length
*/
public PartialPiece (int piece, int len) throws OutOfMemoryError {
public PartialPiece (Piece piece, int len, File tempDir) {
this.piece = piece;
this.bs = new byte[len];
this.off = 0;
this.createdTime = 0;
this.pclen = len;
//this.createdTime = 0;
this.tempDir = tempDir;
// temps for finals
byte[] tbs = null;
try {
if (len <= MAX_IN_MEM) {
try {
tbs = new byte[len];
return;
} catch (OutOfMemoryError oom) {
if (_max_in_mem > PeerState.PARTSIZE)
_max_in_mem /= 2;
Log log = I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class);
log.logAlways(Log.WARN, "OOM creating new partial piece");
// fall through to use temp file
}
}
// delay creating temp file until required in read()
} finally {
// finals
this.bs = tbs;
}
}
/**
* Used by PeerState.
* Creates a new PartialPiece, with chunks up to but not including
* firstOutstandingRequest already downloaded and stored in the Request byte array.
* Caller must synchronize
*
* Note that this cannot handle gaps; chunks after a missing chunk cannot be saved.
* That would be harder.
*
* @param firstOutstandingRequest the first request not fulfilled for the piece
* @since 0.9.1
*/
public PartialPiece (Request firstOutstandingRequest) {
this.piece = firstOutstandingRequest.piece;
this.bs = firstOutstandingRequest.bs;
this.off = firstOutstandingRequest.off;
this.createdTime = System.currentTimeMillis();
private void createTemp() throws IOException {
//tfile = SecureFile.createTempFile("piece", null, tempDir);
// debug
tempfile = SecureFile.createTempFile("piece_" + piece.getId() + '_', null, tempDir);
//I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Created " + tempfile);
// tfile.deleteOnExit() ???
raf = new RandomAccessFile(tempfile, "rw");
// Do not preallocate the file space.
// Not necessary to call setLength(), file is extended when written
//traf.setLength(len);
}
/**
@@ -55,33 +112,200 @@ class PartialPiece implements Comparable {
*/
public Request getRequest() {
return new Request(this.piece, this.bs, this.off, Math.min(this.bs.length - this.off, PeerState.PARTSIZE));
return new Request(this, this.off, Math.min(this.pclen - this.off, PeerState.PARTSIZE));
}
/** piece number */
public int getPiece() {
return this.piece;
return this.piece.getId();
}
/** how many bytes are good */
/**
* @since 0.9.1
*/
public int getLength() {
return this.pclen;
}
/**
* How many bytes are good - only valid by setDownloaded()
*/
public int getDownloaded() {
return this.off;
}
/**
* Call this before returning a PartialPiece to the PeerCoordinator
* @since 0.9.1
*/
public void setDownloaded(int offset) {
this.off = offset;
}
/****
public long getCreated() {
return this.createdTime;
}
****/
/**
* Highest downloaded first
* Piece must be complete.
* The SHA1 hash of the completely read data.
* @since 0.9.1
*/
public byte[] getHash() throws IOException {
MessageDigest sha1 = SHA1.getInstance();
if (bs != null) {
sha1.update(bs);
} else {
int read = 0;
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();
raf.seek(0);
while (read < pclen) {
int rd = raf.read(buf, 0, Math.min(buf.length, pclen - read));
if (rd < 0)
break;
read += rd;
sha1.update(buf, 0, rd);
}
}
if (ba != null)
_cache.release(ba, false);
if (read < pclen)
throw new IOException();
}
return sha1.digest();
}
/**
* Blocking.
* @since 0.9.1
*/
public void read(DataInputStream din, int off, int len) throws IOException {
if (bs != null) {
din.readFully(bs, off, len);
} else {
// read in fully before synching on raf
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)
createTemp();
raf.seek(off);
raf.write(tmp);
}
if (ba != null)
_cache.release(ba, false);
}
}
/**
* Piece must be complete.
* Caller must synchronize on out and seek to starting point.
* Caller must call release() when done with the whole piece.
*
* @param out stream to write to
* @param offset offset in the piece
* @param len length to write
* @since 0.9.1
*/
public void write(DataOutput out, int offset, int len) throws IOException {
if (bs != null) {
out.write(bs, offset, len);
} else {
int read = 0;
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();
raf.seek(offset);
while (read < len) {
int rd = Math.min(buf.length, len - read);
raf.readFully(buf, 0, rd);
read += rd;
out.write(buf, 0, rd);
}
}
if (ba != null)
_cache.release(ba, false);
}
}
/**
* Release all resources.
*
* @since 0.9.1
*/
public void release() {
if (bs == null) {
synchronized (this) {
if (raf != null)
locked_release();
}
//if (raf != null)
// I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Released " + tempfile);
}
}
/**
* Caller must synchronize
*
* @since 0.9.1
*/
private void locked_release() {
try {
raf.close();
} catch (IOException ioe) {
I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Error closing " + raf, ioe);
}
tempfile.delete();
}
/*
* Highest priority first,
* then rarest first,
* then highest downloaded first
*/
public int compareTo(Object o) throws ClassCastException {
return ((PartialPiece)o).off - this.off; // reverse
PartialPiece opp = (PartialPiece)o;
int d = this.piece.compareTo(opp.piece);
if (d != 0)
return d;
return opp.off - this.off; // reverse
}
@Override
public int hashCode() {
return piece * 7777;
return piece.getId() * 7777;
}
/**
@@ -92,13 +316,13 @@ class PartialPiece implements Comparable {
public boolean equals(Object o) {
if (o instanceof PartialPiece) {
PartialPiece pp = (PartialPiece)o;
return pp.piece == this.piece;
return pp.piece.getId() == this.piece.getId();
}
return false;
}
@Override
public String toString() {
return "Partial(" + piece + ',' + off + ',' + bs.length + ')';
return "Partial(" + piece.getId() + ',' + off + ',' + pclen + ')';
}
}

View File

@@ -80,7 +80,9 @@ public class Peer implements Comparable
static final long OPTION_FAST = 0x0000000000000004l;
static final long OPTION_DHT = 0x0000000000000001l;
/** we use a different bit since the compact format is different */
/* no, let's use an extension message
static final long OPTION_I2P_DHT = 0x0000000040000000l;
*/
static final long OPTION_AZMP = 0x1000000000000000l;
private long options;
@@ -268,15 +270,18 @@ public class Peer implements Comparable
if (_log.shouldLog(Log.DEBUG))
_log.debug("Peer supports extensions, sending reply message");
int metasize = metainfo != null ? metainfo.getInfoBytes().length : -1;
out.sendExtension(0, ExtensionHandler.getHandshake(metasize));
boolean pexAndMetadata = metainfo == null || !metainfo.isPrivate();
boolean dht = util.getDHT() != null;
out.sendExtension(0, ExtensionHandler.getHandshake(metasize, pexAndMetadata, dht));
}
if ((options & OPTION_I2P_DHT) != 0 && util.getDHT() != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Peer supports DHT, sending PORT message");
int port = util.getDHT().getPort();
out.sendPort(port);
}
// Old DHT PORT message
//if ((options & OPTION_I2P_DHT) != 0 && util.getDHT() != null) {
// if (_log.shouldLog(Log.DEBUG))
// _log.debug("Peer supports DHT, sending PORT message");
// int port = util.getDHT().getPort();
// out.sendPort(port);
//}
// Send our bitmap
if (bitfield != null)
@@ -459,7 +464,7 @@ public class Peer implements Comparable
if (this.deregister) {
PeerListener p = s.listener;
if (p != null) {
List<PartialPiece> pcs = s.returnPartialPieces();
List<Request> pcs = s.returnPartialPieces();
if (!pcs.isEmpty())
p.savePartialPieces(this, pcs);
// now covered by savePartialPieces

View File

@@ -46,6 +46,10 @@ public class PeerAcceptor
private final PeerCoordinator coordinator;
final PeerCoordinatorSet coordinators;
/** shorten timeout while reading handshake */
private static final long HASH_READ_TIMEOUT = 45*1000;
public PeerAcceptor(PeerCoordinator coordinator)
{
this.coordinator = coordinator;
@@ -69,11 +73,20 @@ public class PeerAcceptor
// talk about, and we can just look for that in our list of active torrents.
byte peerInfoHash[] = null;
if (in instanceof BufferedInputStream) {
// multitorrent
in.mark(LOOKAHEAD_SIZE);
peerInfoHash = readHash(in);
long timeout = socket.getReadTimeout();
socket.setReadTimeout(HASH_READ_TIMEOUT);
try {
peerInfoHash = readHash(in);
} catch (IOException ioe) {
// unique exception so ConnectionAcceptor can blame the peer
throw new ProtocolException(ioe.toString());
}
socket.setReadTimeout(timeout);
in.reset();
} else {
// is this working right?
// Single torrent - is this working right?
try {
peerInfoHash = readHash(in);
if (_log.shouldLog(Log.INFO))
@@ -104,9 +117,8 @@ public class PeerAcceptor
}
} else {
// multitorrent capable, so lets see what we can handle
for (Iterator iter = coordinators.iterator(); iter.hasNext(); ) {
PeerCoordinator cur = (PeerCoordinator)iter.next();
PeerCoordinator cur = coordinators.get(peerInfoHash);
if (cur != null) {
if (DataHelper.eq(cur.getInfoHash(), peerInfoHash)) {
if (cur.needPeers())
{
@@ -130,22 +142,50 @@ public class PeerAcceptor
}
}
private static final String PROTO_STR = "BitTorrent protocol";
private static final int PROTO_STR_LEN = PROTO_STR.length();
private static final int PROTO_LEN = PROTO_STR_LEN + 1;
private static final int[] PROTO = new int[PROTO_LEN];
static {
PROTO[0] = PROTO_STR_LEN;
for (int i = 0; i < PROTO_STR_LEN; i++) {
PROTO[i+1] = PROTO_STR.charAt(i);
}
}
/** 48 */
private static final int LOOKAHEAD_SIZE = 1 + // chr(19)
"BitTorrent protocol".length() +
private static final int LOOKAHEAD_SIZE = PROTO_LEN +
8 + // blank, reserved
20; // infohash
/**
* Read ahead to the infohash, throwing an exception if there isn't enough data
* Read ahead to the infohash, throwing an exception if there isn't enough data.
* Also check the first 20 bytes for the correct protocol here and throw IOE if bad,
* so we don't hang waiting for 48 bytes if it's not a bittorrent client.
* The 20 bytes are checked again in Peer.handshake().
*/
private byte[] readHash(InputStream in) throws IOException {
byte buf[] = new byte[LOOKAHEAD_SIZE];
private static byte[] readHash(InputStream in) throws IOException {
for (int i = 0; i < PROTO_LEN; i++) {
int b = in.read();
if (b != PROTO[i])
throw new IOException("Bad protocol 0x" + Integer.toHexString(b) + " at byte " + i);
}
if (in.skip(8) != 8)
throw new IOException("EOF before hash");
byte buf[] = new byte[20];
int read = DataHelper.read(in, buf);
if (read != buf.length)
throw new IOException("Unable to read the hash (read " + read + ")");
byte rv[] = new byte[20];
System.arraycopy(buf, buf.length-rv.length, rv, 0, rv.length);
return rv;
return buf;
}
/**
* A unique exception so we can tell the ConnectionAcceptor about non-BT connections
* @since 0.9.1
*/
public static class ProtocolException extends IOException {
public ProtocolException(String s) {
super(s);
}
}
}

View File

@@ -21,11 +21,14 @@
package org.klomp.snark;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
import org.klomp.snark.dht.DHT;
/**
* TimerTask that checks for good/bad up/downloader. Works together
@@ -37,16 +40,18 @@ class PeerCheckerTask implements Runnable
private final PeerCoordinator coordinator;
private final I2PSnarkUtil _util;
private final Log _log;
private final Random random;
private int _runCount;
PeerCheckerTask(I2PSnarkUtil util, PeerCoordinator coordinator)
{
_util = util;
_log = util.getContext().logManager().getLog(PeerCheckerTask.class);
random = util.getContext().random();
this.coordinator = coordinator;
}
private static final Random random = I2PAppContext.getGlobalContext().random();
public void run()
{
_runCount++;
@@ -60,9 +65,7 @@ class PeerCheckerTask implements Runnable
long worstdownload = Long.MAX_VALUE;
Peer worstDownloader = null;
int peers = 0;
int uploaders = 0;
int downloaders = 0;
int removedCount = 0;
long uploaded = 0;
@@ -73,6 +76,7 @@ class PeerCheckerTask implements Runnable
List<Peer> removed = new ArrayList();
int uploadLimit = coordinator.allowedUploaders();
boolean overBWLimit = coordinator.overUpBWLimit();
DHT dht = _util.getDHT();
for (Peer peer : peerList) {
// Remove dying peers
@@ -85,12 +89,16 @@ class PeerCheckerTask implements Runnable
continue;
}
peers++;
if (peer.getInactiveTime() > PeerCoordinator.MAX_INACTIVE) {
if (_log.shouldLog(Log.WARN))
_log.warn("Disconnecting peer idle " +
DataHelper.formatDuration(peer.getInactiveTime()) + ": " + peer);
peer.disconnect();
continue;
}
if (!peer.isChoking())
uploaders++;
if (!peer.isChoked() && peer.isInteresting())
downloaders++;
long upload = peer.getUploaded();
uploaded += upload;
@@ -99,14 +107,15 @@ class PeerCheckerTask implements Runnable
peer.setRateHistory(upload, download);
peer.resetCounters();
_util.debug(peer + ":", Snark.DEBUG);
_util.debug(" ul: " + upload*1024/KILOPERSECOND
if (_log.shouldLog(Log.DEBUG)) {
_log.debug(peer + ":"
+ " ul: " + upload*1024/KILOPERSECOND
+ " dl: " + download*1024/KILOPERSECOND
+ " i: " + peer.isInterested()
+ " I: " + peer.isInteresting()
+ " c: " + peer.isChoking()
+ " C: " + peer.isChoked(),
Snark.DEBUG);
+ " C: " + peer.isChoked());
}
// Choke a percentage of them rather than all so it isn't so drastic...
// unless this torrent is over the limit all by itself.
@@ -127,8 +136,8 @@ class PeerCheckerTask implements Runnable
// Check if it still wants pieces from us.
if (!peer.isInterested())
{
_util.debug("Choke uninterested peer: " + peer,
Snark.INFO);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Choke uninterested peer: " + peer);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
@@ -138,8 +147,8 @@ class PeerCheckerTask implements Runnable
}
else if (overBWLimitChoke)
{
_util.debug("BW limit (" + upload + "/" + uploaded + "), choke peer: " + peer,
Snark.INFO);
if (_log.shouldLog(Log.DEBUG))
_log.debug("BW limit (" + upload + "/" + uploaded + "), choke peer: " + peer);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
@@ -151,7 +160,8 @@ class PeerCheckerTask implements Runnable
else if (peer.isInteresting() && peer.isChoked())
{
// If they are choking us make someone else a downloader
_util.debug("Choke choking peer: " + peer, Snark.DEBUG);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Choke choking peer: " + peer);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
@@ -163,7 +173,8 @@ class PeerCheckerTask implements Runnable
else if (!peer.isInteresting() && !coordinator.completed())
{
// If they aren't interesting make someone else a downloader
_util.debug("Choke uninteresting peer: " + peer, Snark.DEBUG);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Choke uninteresting peer: " + peer);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
@@ -177,8 +188,8 @@ class PeerCheckerTask implements Runnable
&& download == 0)
{
// We are downloading but didn't receive anything...
_util.debug("Choke downloader that doesn't deliver:"
+ peer, Snark.DEBUG);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Choke downloader that doesn't deliver: " + peer);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
@@ -205,10 +216,13 @@ class PeerCheckerTask implements Runnable
// send PEX
if ((_runCount % 17) == 0 && !peer.isCompleted())
coordinator.sendPeers(peer);
peer.keepAlive();
// cheap failsafe for seeds connected to seeds, stop pinging and hopefully
// the inactive checker (above) will eventually disconnect it
if (coordinator.getNeededLength() > 0 || !peer.isCompleted())
peer.keepAlive();
// announce them to local tracker (TrackerClient does this too)
if (_util.getDHT() != null && (_runCount % 5) == 0) {
_util.getDHT().announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash());
if (dht != null && (_runCount % 5) == 0) {
dht.announce(coordinator.getInfoHash(), peer.getPeerID().getDestHash());
}
}
@@ -222,8 +236,8 @@ class PeerCheckerTask implements Runnable
|| uploaders > uploadLimit)
&& worstDownloader != null)
{
_util.debug("Choke worst downloader: " + worstDownloader,
Snark.DEBUG);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Choke worst downloader: " + worstDownloader);
worstDownloader.setChoking(true);
coordinator.uploaders--;
@@ -256,8 +270,8 @@ class PeerCheckerTask implements Runnable
}
// announce ourselves to local tracker (TrackerClient does this too)
if (_util.getDHT() != null && (_runCount % 16) == 0) {
_util.getDHT().announce(coordinator.getInfoHash());
if (dht != null && (_runCount % 16) == 0) {
dht.announce(coordinator.getInfoHash());
}
}
}

View File

@@ -148,11 +148,9 @@ class PeerConnectionIn implements Runnable
begin = din.readInt();
len = i-9;
Request req = ps.getOutstandingRequest(piece, begin, len);
byte[] piece_bytes;
if (req != null)
{
piece_bytes = req.bs;
din.readFully(piece_bytes, begin, len);
req.read(din);
ps.pieceMessage(req);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received data(" + piece + "," + begin + ") from " + peer);
@@ -160,8 +158,9 @@ class PeerConnectionIn implements Runnable
else
{
// XXX - Consume but throw away afterwards.
piece_bytes = new byte[len];
din.readFully(piece_bytes);
int rcvd = din.skipBytes(len);
if (rcvd != len)
throw new IOException("EOF reading unwanted data");
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received UNWANTED data(" + piece + "," + begin + ") from " + peer);
}

View File

@@ -143,7 +143,7 @@ class PeerConnectionOut implements Runnable
}
}
if (m == null && !sendQueue.isEmpty()) {
m = (Message)sendQueue.remove(0);
m = sendQueue.remove(0);
//SimpleTimer.getInstance().removeEvent(m.expireEvent);
}
}
@@ -395,7 +395,7 @@ class PeerConnectionOut implements Runnable
while (it.hasNext())
{
Message m = (Message)it.next();
if (m.type == Message.REQUEST && m.piece == req.piece &&
if (m.type == Message.REQUEST && m.piece == req.getPiece() &&
m.begin == req.off && m.length == req.len)
{
if (_log.shouldLog(Log.DEBUG))
@@ -406,7 +406,7 @@ class PeerConnectionOut implements Runnable
}
Message m = new Message();
m.type = Message.REQUEST;
m.piece = req.piece;
m.piece = req.getPiece();
m.begin = req.off;
m.length = req.len;
addMessage(m);
@@ -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.
@@ -492,7 +494,7 @@ class PeerConnectionOut implements Runnable
{
Message m = (Message)it.next();
if (m.type == Message.REQUEST
&& m.piece == req.piece
&& m.piece == req.getPiece()
&& m.begin == req.off
&& m.length == req.len)
it.remove();
@@ -502,7 +504,7 @@ class PeerConnectionOut implements Runnable
// Always send, just to be sure it it is really canceled.
Message m = new Message();
m.type = Message.CANCEL;
m.piece = req.piece;
m.piece = req.getPiece();
m.begin = req.off;
m.length = req.len;
addMessage(m);

View File

@@ -22,6 +22,7 @@ package org.klomp.snark;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@@ -34,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;
@@ -48,7 +50,7 @@ import org.klomp.snark.dht.DHT;
/**
* Coordinates what peer does what.
*/
public class PeerCoordinator implements PeerListener
class PeerCoordinator implements PeerListener
{
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerCoordinator.class);
@@ -68,6 +70,7 @@ public class PeerCoordinator implements PeerListener
// package local for access by CheckDownLoadersTask
final static long CHECK_PERIOD = 40*1000; // 40 seconds
final static int MAX_UPLOADERS = 6;
public static final long MAX_INACTIVE = 8*60*1000;
/**
* Approximation of the number of current uploaders.
@@ -116,15 +119,21 @@ public class PeerCoordinator implements PeerListener
*/
private final List<Piece> wantedPieces;
/** partial pieces - lock by synching on wantedPieces */
/** The total number of bytes in wantedPieces, or -1 if not yet known.
* Sync on wantedPieces.
* @since 0.9.1
*/
private long wantedBytes;
/** partial pieces - lock by synching on wantedPieces - TODO store Requests, not PartialPieces */
private final List<PartialPiece> partialPieces;
private boolean halted = false;
private volatile boolean halted;
private final MagnetState magnetState;
private final CoordinatorListener listener;
private final I2PSnarkUtil _util;
private static final Random _random = I2PAppContext.getGlobalContext().random();
private final Random _random;
/**
* @param metainfo null if in magnet mode
@@ -134,6 +143,7 @@ public class PeerCoordinator implements PeerListener
CoordinatorListener listener, Snark torrent)
{
_util = util;
_random = util.getContext().random();
this.id = id;
this.infohash = infohash;
this.metainfo = metainfo;
@@ -151,7 +161,7 @@ public class PeerCoordinator implements PeerListener
// Install a timer to check the uploaders.
// Randomize the first start time so multiple tasks are spread out,
// this will help the behavior with global limits
timer = new CheckEvent(new PeerCheckerTask(_util, this));
timer = new CheckEvent(_util.getContext(), new PeerCheckerTask(_util, this));
timer.schedule((CHECK_PERIOD / 2) + _random.nextInt((int) CHECK_PERIOD));
}
@@ -161,8 +171,8 @@ public class PeerCoordinator implements PeerListener
*/
private static class CheckEvent extends SimpleTimer2.TimedEvent {
private final PeerCheckerTask _task;
public CheckEvent(PeerCheckerTask task) {
super(SimpleTimer2.getInstance());
public CheckEvent(I2PAppContext ctx, PeerCheckerTask task) {
super(ctx.simpleTimer2());
_task = task;
}
public void timeReached() {
@@ -171,16 +181,22 @@ public class PeerCoordinator implements PeerListener
}
}
// only called externally from Storage after the double-check fails
/**
* Only called externally from Storage after the double-check fails.
* Sets wantedBytes too.
*/
public void setWantedPieces()
{
if (metainfo == null || storage == null)
if (metainfo == null || storage == null) {
wantedBytes = -1;
return;
}
// Make a list of pieces
synchronized(wantedPieces) {
wantedPieces.clear();
BitField bitfield = storage.getBitField();
int[] pri = storage.getPiecePriorities();
long count = 0;
for (int i = 0; i < metainfo.getPieces(); i++) {
// only add if we don't have and the priority is >= 0
if ((!bitfield.get(i)) &&
@@ -189,15 +205,17 @@ public class PeerCoordinator implements PeerListener
if (pri != null)
p.setPriority(pri[i]);
wantedPieces.add(p);
count += metainfo.getPieceLength(i);
}
}
wantedBytes = count;
Collections.shuffle(wantedPieces, _random);
}
}
public Storage getStorage() { return storage; }
// for web page detailed stats
/** for web page detailed stats */
public List<Peer> peerList()
{
return new ArrayList(peers);
@@ -233,7 +251,9 @@ public class PeerCoordinator implements PeerListener
}
/**
* Returns how many bytes are still needed to get the complete file.
* Bytes not yet in storage. Does NOT account for skipped files.
* Not exact (does not adjust for last piece size).
* Returns how many bytes are still needed to get the complete torrent.
* @return -1 if in magnet mode
*/
public long getLeft()
@@ -244,6 +264,15 @@ public class PeerCoordinator implements PeerListener
return ((long) storage.needed()) * metainfo.getPieceLength(0);
}
/**
* Bytes still wanted. DOES account for skipped files.
* @return exact value. or -1 if no storage yet.
* @since 0.9.1
*/
public long getNeededLength() {
return wantedBytes;
}
/**
* Returns the total number of uploaded bytes of all peers.
*/
@@ -330,14 +359,35 @@ public class PeerCoordinator implements PeerListener
return infohash;
}
/**
* Inbound.
* Not halted, peers < max.
* @since 0.9.1
*/
public boolean needPeers()
{
return !halted && peers.size() < getMaxConnections();
}
/**
* Outbound.
* Not halted, peers < max, and need pieces.
* @since 0.9.1
*/
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 &&
(storage == null || !storage.isChecking());
}
/**
* Reduce max if huge pieces to keep from ooming when leeching
* @return 512K: 16; 1M: 11; 2M: 6
* Formerly used to
* reduce max if huge pieces to keep from ooming when leeching
* but now we don't
* @return usually 16
*/
private int getMaxConnections() {
if (metainfo == null)
@@ -347,13 +397,14 @@ public class PeerCoordinator implements PeerListener
return 4;
if (pieces <= 5)
return 6;
int size = metainfo.getPieceLength(0);
//int size = metainfo.getPieceLength(0);
int max = _util.getMaxConnections();
if (size <= 512*1024 || completed())
// Now that we use temp files, no memory concern
//if (size <= 512*1024 || completed())
return max;
if (size <= 1024*1024)
return (max + max + 2) / 3;
return (max + 2) / 3;
//if (size <= 1024*1024)
// return (max + max + 2) / 3;
//return (max + 2) / 3;
}
public boolean halted() { return halted; }
@@ -380,10 +431,33 @@ public class PeerCoordinator implements PeerListener
}
// delete any saved orphan partial piece
synchronized (partialPieces) {
for (PartialPiece pp : partialPieces) {
pp.release();
}
partialPieces.clear();
}
}
/**
* @since 0.9.1
*/
public void restart() {
halted = false;
synchronized (uploaded_old) {
Arrays.fill(uploaded_old, 0);
}
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));
}
public void connected(Peer peer)
{
if (halted)
@@ -396,7 +470,7 @@ public class PeerCoordinator implements PeerListener
synchronized(peers)
{
Peer old = peerIDInList(peer.getPeerID(), peers);
if ( (old != null) && (old.getInactiveTime() > 8*60*1000) ) {
if ( (old != null) && (old.getInactiveTime() > MAX_INACTIVE) ) {
// idle for 8 minutes, kill the old con (32KB/8min = 68B/sec minimum for one block)
if (_log.shouldLog(Log.WARN))
_log.warn("Remomving old peer: " + peer + ": " + old + ", inactive for " + old.getInactiveTime());
@@ -444,8 +518,8 @@ public 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) {
@@ -468,7 +542,10 @@ public class PeerCoordinator implements PeerListener
return null;
}
// returns true if actual attempt to add peer occurs
/**
* Add peer (inbound or outbound)
* @return true if actual attempt to add peer occurs
*/
public boolean addPeer(final Peer peer)
{
if (halted)
@@ -487,7 +564,7 @@ public class PeerCoordinator implements PeerListener
need_more = (!peer.isConnected()) && peersize < getMaxConnections();
// Check if we already have this peer before we build the connection
Peer old = peerIDInList(peer.getPeerID(), peers);
need_more = need_more && ((old == null) || (old.getInactiveTime() > 8*60*1000));
need_more = need_more && ((old == null) || (old.getInactiveTime() > MAX_INACTIVE));
}
if (need_more)
@@ -578,13 +655,18 @@ public 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;
}
}
/**
@@ -593,23 +675,20 @@ public 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;
}
/**
@@ -630,22 +709,23 @@ public class PeerCoordinator implements PeerListener
* -1 if none of the given pieces are wanted.
*/
public int wantPiece(Peer peer, BitField havePieces) {
return wantPiece(peer, havePieces, true);
Piece pc = wantPiece(peer, havePieces, true);
return pc != null ? pc.getId() : -1;
}
/**
* Returns one of pieces in the given BitField that is still wanted or
* -1 if none of the given pieces are wanted.
* null if none of the given pieces are wanted.
*
* @param record if true, actually record in our data structures that we gave the
* request to this peer. If false, do not update the data structures.
* @since 0.8.2
*/
private int wantPiece(Peer peer, BitField havePieces, boolean record) {
private Piece wantPiece(Peer peer, BitField havePieces, boolean record) {
if (halted) {
if (_log.shouldLog(Log.WARN))
_log.warn("We don't want anything from the peer, as we are halted! peer=" + peer);
return -1;
return null;
}
Piece piece = null;
@@ -664,7 +744,19 @@ public 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())
{
@@ -679,8 +771,12 @@ public 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)
return -1; // nothing to request and not in end game
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)
@@ -704,7 +800,7 @@ public class PeerCoordinator implements PeerListener
_log.warn("nothing to even rerequest from " + peer + ": requested = " + requested);
// _log.warn("nothing to even rerequest from " + peer + ": requested = " + requested
// + " wanted = " + wantedPieces + " peerHas = " + havePieces);
return -1; //If we still can't find a piece we want, so be it.
return null; //If we still can't find a piece we want, so be it.
} else {
// Should be a lot smarter here -
// share blocks rather than starting from 0 with each peer.
@@ -716,10 +812,11 @@ public 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.getId();
return piece;
} // synch
}
@@ -736,6 +833,7 @@ public class PeerCoordinator implements PeerListener
_log.debug("Updated piece priorities called but no priorities to set?");
return;
}
List<Piece> toCancel = new ArrayList();
synchronized(wantedPieces) {
// Add incomplete and previously unwanted pieces to the list
// Temp to avoid O(n**2)
@@ -749,6 +847,7 @@ public class PeerCoordinator implements PeerListener
if (!want.get(i)) {
Piece piece = new Piece(i);
wantedPieces.add(piece);
wantedBytes += metainfo.getPieceLength(i);
// As connections are already up, new Pieces will
// not have their PeerID list populated, so do that.
for (Peer p : peers) {
@@ -770,23 +869,32 @@ public class PeerCoordinator implements PeerListener
p.setPriority(priority);
} else {
iter.remove();
// cancel all peers
for (Peer peer : peers) {
peer.cancel(p.getId());
}
toCancel.add(p);
wantedBytes -= metainfo.getPieceLength(p.getId());
}
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Updated piece priorities, now wanted: " + wantedPieces);
// if we added pieces, they will be in-order unless we shuffle
Collections.shuffle(wantedPieces, _random);
}
// update request queues, in case we added wanted pieces
// and we were previously uninterested
for (Peer peer : peers) {
peer.request();
// cancel outside of wantedPieces lock to avoid deadlocks
if (!toCancel.isEmpty()) {
// cancel all peers
for (Peer peer : peers) {
for (Piece p : toCancel) {
peer.cancel(p.getId());
}
}
}
// ditto, avoid deadlocks
// update request queues, in case we added wanted pieces
// and we were previously uninterested
for (Peer peer : peers) {
peer.request();
}
}
/**
@@ -795,7 +903,7 @@ public 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;
@@ -811,8 +919,10 @@ public class PeerCoordinator implements PeerListener
snark.stopTorrent();
String msg = "Error reading the storage (piece " + piece + ") for " + metainfo.getName() + ": " + ioe;
_log.error(msg, ioe);
SnarkManager.instance().addMessage(msg);
SnarkManager.instance().addMessage("Fatal storage error: Stopping torrent " + metainfo.getName());
if (listener != null) {
listener.addMessage(msg);
listener.addMessage("Fatal storage error: Stopping torrent " + metainfo.getName());
}
throw new RuntimeException(msg, ioe);
}
}
@@ -824,8 +934,8 @@ public class PeerCoordinator implements PeerListener
{
uploaded += size;
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
}
/**
@@ -835,8 +945,8 @@ public class PeerCoordinator implements PeerListener
{
downloaded += size;
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
}
/**
@@ -846,14 +956,13 @@ public class PeerCoordinator implements PeerListener
*
* @throws RuntimeException on IOE saving the piece
*/
public boolean gotPiece(Peer peer, int piece, byte[] bs)
public boolean gotPiece(Peer peer, PartialPiece pp)
{
if (metainfo == null || storage == null)
if (metainfo == null || storage == null || storage.isChecking() || halted) {
pp.release();
return true;
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)
{
@@ -866,13 +975,16 @@ public 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
{
if (storage.putPiece(piece, bs))
// this takes forever if complete, as it rechecks
if (storage.putPiece(pp))
{
if (_log.shouldLog(Log.INFO))
_log.info("Got valid piece " + piece + "/" + metainfo.getPieces() +" from " + peer + " for " + metainfo.getName());
@@ -890,38 +1002,51 @@ public class PeerCoordinator implements PeerListener
snark.stopTorrent();
String msg = "Error writing storage (piece " + piece + ") for " + metainfo.getName() + ": " + ioe;
_log.error(msg, ioe);
SnarkManager.instance().addMessage(msg);
SnarkManager.instance().addMessage("Fatal storage error: Stopping torrent " + metainfo.getName());
if (listener != null) {
listener.addMessage(msg);
listener.addMessage("Fatal storage error: Stopping torrent " + metainfo.getName());
}
throw new RuntimeException(msg, ioe);
}
wantedPieces.remove(p);
wantedBytes -= metainfo.getPieceLength(p.getId());
}
// just in case
removePartialPiece(piece);
boolean done = wantedBytes <= 0;
// Announce to the world we have it!
// Disconnect from other seeders when we get the last piece
List<Peer> toDisconnect = new ArrayList();
Iterator<Peer> it = peers.iterator();
while (it.hasNext())
{
Peer p = it.next();
List<Peer> toDisconnect = done ? new ArrayList() : null;
for (Peer p : peers) {
if (p.isConnected())
{
if (completed() && p.isCompleted())
if (done && p.isCompleted())
toDisconnect.add(p);
else
p.have(piece);
}
}
it = toDisconnect.iterator();
while (it.hasNext())
{
Peer p = it.next();
}
if (done) {
for (Peer p : toDisconnect) {
p.disconnect(true);
}
}
// put msg on the console if partial, since Storage won't do it
if (!completed())
snark.storageCompleted(storage);
synchronized (partialPieces) {
for (PartialPiece ppp : partialPieces) {
ppp.release();
}
partialPieces.clear();
}
}
return true;
}
@@ -931,8 +1056,8 @@ public 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)
@@ -951,8 +1076,8 @@ public class PeerCoordinator implements PeerListener
}
}
if (listener != null)
listener.peerChange(this, peer);
//if (listener != null)
// listener.peerChange(this, peer);
}
public void disconnected(Peer peer)
@@ -972,18 +1097,18 @@ public 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);
}
}
}
@@ -998,17 +1123,24 @@ public class PeerCoordinator implements PeerListener
* Also mark the piece unrequested if this peer was the only one.
*
* @param peer partials, must include the zero-offset (empty) ones too
* No dup pieces, piece.setDownloaded() must be set
* @since 0.8.2
*/
public void savePartialPieces(Peer peer, List<PartialPiece> partials)
public void savePartialPieces(Peer peer, List<Request> partials)
{
if (halted)
return;
if (_log.shouldLog(Log.INFO))
_log.info("Partials received from " + peer + ": " + partials);
if (halted || completed()) {
for (Request req : partials) {
PartialPiece pp = req.getPartialPiece();
pp.release();
}
return;
}
synchronized(wantedPieces) {
for (PartialPiece pp : partials) {
if (pp.getDownloaded() > 0) {
for (Request req : partials) {
PartialPiece pp = req.getPartialPiece();
if (req.off > 0) {
// PartialPiece.equals() only compares piece number, which is what we want
int idx = partialPieces.indexOf(pp);
if (idx < 0) {
@@ -1017,10 +1149,12 @@ public class PeerCoordinator implements PeerListener
_log.info("Saving orphaned partial piece (new) " + pp);
} else if (idx >= 0 && pp.getDownloaded() > partialPieces.get(idx).getDownloaded()) {
// replace what's there now
partialPieces.get(idx).release();
partialPieces.set(idx, pp);
if (_log.shouldLog(Log.INFO))
_log.info("Saving orphaned partial piece (bigger) " + pp);
} else {
pp.release();
if (_log.shouldLog(Log.INFO))
_log.info("Discarding partial piece (not bigger)" + pp);
}
@@ -1029,10 +1163,14 @@ public class PeerCoordinator implements PeerListener
// sorts by remaining bytes, least first
Collections.sort(partialPieces);
PartialPiece gone = partialPieces.remove(max);
gone.release();
if (_log.shouldLog(Log.INFO))
_log.info("Discarding orphaned partial piece (list full)" + gone);
}
} // else drop the empty partial piece
} else {
// drop the empty partial piece
pp.release();
}
// synchs on wantedPieces...
markUnrequested(peer, pp.getPiece());
}
@@ -1051,6 +1189,8 @@ public 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);
@@ -1058,10 +1198,31 @@ public class PeerCoordinator implements PeerListener
PartialPiece pp = iter.next();
int savedPiece = pp.getPiece();
if (havePieces.get(savedPiece)) {
iter.remove();
// this is just a double-check, it should be in there
boolean skipped = false;
for(Piece piece : wantedPieces) {
if (piece.getId() == savedPiece) {
if (peer.isCompleted() && piece.getPeerCount() > 1) {
// Try to preserve rarest-first
// by not requesting a partial piece that non-seeders also have
// from a seeder
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);
if (_log.shouldLog(Log.INFO)) {
_log.info("Restoring orphaned partial piece " + pp +
@@ -1070,8 +1231,12 @@ public class PeerCoordinator implements PeerListener
return pp;
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Partial piece " + pp + " NOT in wantedPieces??");
if (_log.shouldLog(Log.WARN)) {
if (skipped)
_log.warn("Partial piece " + pp + " with multiple peers skipped for seeder");
else
_log.warn("Partial piece " + pp + " NOT in wantedPieces??");
}
}
}
if (_log.shouldLog(Log.WARN) && !partialPieces.isEmpty())
@@ -1079,14 +1244,9 @@ public class PeerCoordinator implements PeerListener
}
// ...and this section turns this into the general move-requests-around code!
// Temporary? So PeerState never calls wantPiece() directly for now...
int piece = wantPiece(peer, havePieces);
if (piece >= 0) {
try {
return new PartialPiece(piece, metainfo.getPieceLength(piece));
} catch (OutOfMemoryError oom) {
if (_log.shouldLog(Log.WARN))
_log.warn("OOM creating new partial piece");
}
Piece piece = wantPiece(peer, havePieces, true);
if (piece != null) {
return new PartialPiece(piece, metainfo.getPieceLength(piece.getId()), _util.getTempDir());
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("We have no partial piece to return");
@@ -1121,7 +1281,7 @@ public class PeerCoordinator implements PeerListener
}
}
}
return wantPiece(peer, havePieces, false) >= 0;
return wantPiece(peer, havePieces, false) != null;
}
/**
@@ -1135,6 +1295,7 @@ public 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
}
}
@@ -1176,6 +1337,7 @@ public class PeerCoordinator implements PeerListener
}
} else if (id == ExtensionHandler.ID_HANDSHAKE) {
sendPeers(peer);
sendDHT(peer);
}
}
@@ -1186,6 +1348,8 @@ public class PeerCoordinator implements PeerListener
* @since 0.8.4
*/
void sendPeers(Peer peer) {
if (metainfo != null && metainfo.isPrivate())
return;
Map<String, BEValue> handshake = peer.getHandshakeMap();
if (handshake == null)
return;
@@ -1202,6 +1366,26 @@ public class PeerCoordinator implements PeerListener
} catch (InvalidBEncodingException ibee) {}
}
/**
* Send a DHT message to the peer, if we both support DHT.
* @since DHT
*/
void sendDHT(Peer peer) {
DHT dht = _util.getDHT();
if (dht == null)
return;
Map<String, BEValue> handshake = peer.getHandshakeMap();
if (handshake == null)
return;
BEValue bev = handshake.get("m");
if (bev == null)
return;
try {
if (bev.getMap().get(ExtensionHandler.TYPE_DHT) != null)
ExtensionHandler.sendDHT(peer, dht.getPort(), dht.getRPort());
} catch (InvalidBEncodingException ibee) {}
}
/**
* Sets the storage after transition out of magnet mode
* Snark calls this after we call gotMetaInfo()
@@ -1219,20 +1403,23 @@ public class PeerCoordinator implements PeerListener
/**
* PeerListener callback
* Tell the DHT to ping it, this will get back the node info
* @param rport must be port + 1
* @since 0.8.4
*/
public void gotPort(Peer peer, int port) {
public void gotPort(Peer peer, int port, int rport) {
DHT dht = _util.getDHT();
if (dht != null)
if (dht != null &&
port > 0 && port < 65535 && rport == port + 1)
dht.ping(peer.getDestination(), port);
}
/**
* Get peers from PEX -
* PeerListener callback
* @since 0.8.4
*/
public void gotPeers(Peer peer, List<PeerID> peers) {
if (completed() || !needPeers())
if (!needOutboundPeers())
return;
Destination myDest = _util.getMyDestination();
if (myDest == null)
@@ -1252,6 +1439,7 @@ public 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() {
@@ -1294,5 +1482,13 @@ public class PeerCoordinator implements PeerListener
return listener.overUpBWLimit(total * 1000 / CHECK_PERIOD);
return false;
}
/**
* Convenience
* @since 0.9.2
*/
public I2PSnarkUtil getUtil() {
return _util;
}
}

View File

@@ -1,9 +1,10 @@
package org.klomp.snark;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.crypto.SHA1Hash;
/**
* Hmm, any guesses as to what this is? Used by the multitorrent functionality
@@ -12,26 +13,28 @@ import java.util.Set;
* from it there too)
*/
public class PeerCoordinatorSet {
private final Set _coordinators;
private final Map<SHA1Hash, PeerCoordinator> _coordinators;
public PeerCoordinatorSet() {
_coordinators = new HashSet();
_coordinators = new ConcurrentHashMap();
}
public Iterator iterator() {
synchronized (_coordinators) {
return new ArrayList(_coordinators).iterator();
}
public Iterator<PeerCoordinator> iterator() {
return _coordinators.values().iterator();
}
public void add(PeerCoordinator coordinator) {
synchronized (_coordinators) {
_coordinators.add(coordinator);
}
_coordinators.put(new SHA1Hash(coordinator.getInfoHash()), coordinator);
}
public void remove(PeerCoordinator coordinator) {
synchronized (_coordinators) {
_coordinators.remove(coordinator);
}
_coordinators.remove(new SHA1Hash(coordinator.getInfoHash()));
}
/**
* @since 0.9.2
*/
public PeerCoordinator get(byte[] infoHash) {
return _coordinators.get(new SHA1Hash(infoHash));
}
}

View File

@@ -52,6 +52,7 @@ public class PeerID implements Comparable
/** whether we have tried to get the dest from the hash - only do once */
private boolean triedDestLookup;
private final int hash;
private final I2PSnarkUtil util;
public PeerID(byte[] id, Destination address)
{
@@ -60,6 +61,7 @@ public class PeerID implements Comparable
this.port = 6881;
this.destHash = address.calculateHash().getData();
hash = calculateHash();
util = null;
}
/**
@@ -93,13 +95,15 @@ public class PeerID implements Comparable
port = 6881;
this.destHash = address.calculateHash().getData();
hash = calculateHash();
util = null;
}
/**
* Creates a PeerID from a destHash
* @param util for eventual destination lookup
* @since 0.8.1
*/
public PeerID(byte[] dest_hash) throws InvalidBEncodingException
public PeerID(byte[] dest_hash, I2PSnarkUtil util) throws InvalidBEncodingException
{
// id and address remain null
port = 6881;
@@ -107,6 +111,7 @@ public class PeerID implements Comparable
throw new InvalidBEncodingException("bad hash length");
destHash = dest_hash;
hash = DataHelper.hashCode(dest_hash);
this.util = util;
}
public byte[] getID()
@@ -131,7 +136,7 @@ public class PeerID implements Comparable
{
if (address == null && destHash != null && !triedDestLookup) {
String b32 = Base32.encode(destHash) + ".b32.i2p";
address = I2PAppContext.getGlobalContext().namingService().lookup(b32);
address = util.getDestination(b32);
triedDestLookup = true;
}
return address;

View File

@@ -22,6 +22,8 @@ package org.klomp.snark;
import java.util.List;
import net.i2p.data.ByteArray;
/**
* Listener for Peer events.
*/
@@ -95,12 +97,11 @@ interface PeerListener
* will be closed.
*
* @param peer the Peer that got the piece.
* @param piece the piece number received.
* @param bs the byte array containing the piece.
* @param piece the piece received.
*
* @return true when the bytes represent the piece, false otherwise.
*/
boolean gotPiece(Peer peer, int piece, byte[] bs);
boolean gotPiece(Peer peer, PartialPiece piece);
/**
* Called when the peer wants (part of) a piece from us. Only called
@@ -115,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.
@@ -167,7 +168,7 @@ interface PeerListener
* @param peer the peer
* @since 0.8.2
*/
void savePartialPieces(Peer peer, List<PartialPiece> pcs);
void savePartialPieces(Peer peer, List<Request> pcs);
/**
* Called when a peer has connected and there may be a partially
@@ -191,13 +192,14 @@ interface PeerListener
void gotExtension(Peer peer, int id, byte[] bs);
/**
* Called when a port message is received.
* Called when a DHT port message is received.
*
* @param peer the Peer that got the message.
* @param port the port
* @param port the query port
* @param rport the response port
* @since 0.8.4
*/
void gotPort(Peer peer, int port);
void gotPort(Peer peer, int port, int rport);
/**
* Called when peers are received via PEX
@@ -207,4 +209,10 @@ interface PeerListener
* @since 0.8.4
*/
void gotPeers(Peer peer, List<PeerID> pIDList);
/**
* Convenience
* @since 0.9.2
*/
public I2PSnarkUtil getUtil();
}

View File

@@ -20,16 +20,14 @@
package org.klomp.snark;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.util.Log;
class PeerState implements DataLoader
@@ -42,13 +40,13 @@ class PeerState implements DataLoader
// Interesting and choking describes whether we are interested in or
// are choking the other side.
boolean interesting = false;
boolean choking = true;
volatile boolean interesting;
volatile boolean choking = true;
// Interested and choked describes whether the other side is
// interested in us or choked us.
boolean interested = false;
boolean choked = true;
volatile boolean interested;
volatile boolean choked = true;
/** the pieces the peer has */
BitField bitfield;
@@ -110,7 +108,7 @@ class PeerState implements DataLoader
// The only problem with returning the partials to the coordinator
// is that chunks above a missing request are lost.
// Future enhancements to PartialPiece could keep track of the holes.
List<PartialPiece> pcs = returnPartialPieces();
List<Request> pcs = returnPartialPieces();
if (!pcs.isEmpty()) {
if (_log.shouldLog(Log.DEBUG))
_log.debug(peer + " got choked, returning partial pieces to the PeerCoordinator: " + pcs);
@@ -234,8 +232,8 @@ class PeerState implements DataLoader
return;
}
if (_log.shouldLog(Log.INFO))
_log.info("Queueing (" + piece + ", " + begin + ", "
if (_log.shouldLog(Log.DEBUG))
_log.debug("Queueing (" + piece + ", " + begin + ", "
+ length + ")" + " to " + peer);
// don't load the data into mem now, let PeerConnectionOut do it
@@ -248,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?
@@ -259,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))
@@ -270,8 +268,8 @@ class PeerState implements DataLoader
return null;
}
if (_log.shouldLog(Log.INFO))
_log.info("Sending (" + piece + ", " + begin + ", "
if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending (" + piece + ", " + begin + ", "
+ length + ")" + " to " + peer);
return pieceBytes;
}
@@ -307,22 +305,23 @@ class PeerState implements DataLoader
if (_log.shouldLog(Log.DEBUG))
_log.debug("got end of Chunk("
+ req.piece + "," + req.off + "," + req.len + ") from "
+ req.getPiece() + "," + req.off + "," + req.len + ") from "
+ peer);
// Last chunk needed for this piece?
if (getFirstOutstandingRequest(req.piece) == -1)
// FIXME if priority changed to skip, we will think we're done when we aren't
if (getFirstOutstandingRequest(req.getPiece()) == -1)
{
// warning - may block here for a while
if (listener.gotPiece(peer, req.piece, req.bs))
if (listener.gotPiece(peer, req.getPartialPiece()))
{
if (_log.shouldLog(Log.DEBUG))
_log.debug("Got " + req.piece + ": " + peer);
_log.debug("Got " + req.getPiece() + ": " + peer);
}
else
{
if (_log.shouldLog(Log.WARN))
_log.warn("Got BAD " + req.piece + " from " + peer);
_log.warn("Got BAD " + req.getPiece() + " from " + peer);
}
}
@@ -338,7 +337,7 @@ class PeerState implements DataLoader
synchronized private int getFirstOutstandingRequest(int piece)
{
for (int i = 0; i < outstandingRequests.size(); i++)
if (outstandingRequests.get(i).piece == piece)
if (outstandingRequests.get(i).getPiece() == piece)
return i;
return -1;
}
@@ -357,24 +356,23 @@ 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.piece == piece && req.off != begin
while (req.getPiece() == piece && req.off != begin
&& r < outstandingRequests.size() - 1)
{
r++;
@@ -382,7 +380,7 @@ class PeerState implements DataLoader
}
// Something wrong?
if (req.piece != piece || req.off != begin || req.len != length)
if (req.getPiece() != piece || req.off != begin || req.len != length)
{
if (_log.shouldLog(Log.INFO))
_log.info("Unrequested or unneeded 'piece: "
@@ -430,13 +428,13 @@ class PeerState implements DataLoader
Request rv = null;
int lowest = Integer.MAX_VALUE;
for (Request r : outstandingRequests) {
if (r.piece == piece && r.off < lowest) {
if (r.getPiece() == piece && r.off < lowest) {
lowest = r.off;
rv = r;
}
}
if (pendingRequest != null &&
pendingRequest.piece == piece && pendingRequest.off < lowest)
pendingRequest.getPiece() == piece && pendingRequest.off < lowest)
rv = pendingRequest;
if (_log.shouldLog(Log.DEBUG))
@@ -450,14 +448,16 @@ class PeerState implements DataLoader
* @return List of PartialPieces, even those with an offset == 0, or empty list
* @since 0.8.2
*/
synchronized List<PartialPiece> returnPartialPieces()
synchronized List<Request> returnPartialPieces()
{
Set<Integer> pcs = getRequestedPieces();
List<PartialPiece> rv = new ArrayList(pcs.size());
List<Request> rv = new ArrayList(pcs.size());
for (Integer p : pcs) {
Request req = getLowestOutstandingRequest(p.intValue());
if (req != null)
rv.add(new PartialPiece(req));
if (req != null) {
req.getPartialPiece().setDownloaded(req.off);
rv.add(req);
}
}
outstandingRequests.clear();
pendingRequest = null;
@@ -471,9 +471,9 @@ class PeerState implements DataLoader
synchronized private Set<Integer> getRequestedPieces() {
Set<Integer> rv = new HashSet(outstandingRequests.size() + 1);
for (Request req : outstandingRequests) {
rv.add(Integer.valueOf(req.piece));
rv.add(Integer.valueOf(req.getPiece()));
if (pendingRequest != null)
rv.add(Integer.valueOf(pendingRequest.piece));
rv.add(Integer.valueOf(pendingRequest.getPiece()));
}
return rv;
}
@@ -489,6 +489,13 @@ class PeerState implements DataLoader
/** @since 0.8.2 */
void extensionMessage(int id, byte[] bs)
{
if (metainfo != null && metainfo.isPrivate() &&
(id == ExtensionHandler.ID_METADATA || id == ExtensionHandler.ID_PEX)) {
// shouldn't get this since we didn't advertise it but they could send it anyway
if (_log.shouldLog(Log.WARN))
_log.warn("Private torrent, ignoring ext msg " + id);
return;
}
ExtensionHandler.handleMessage(peer, listener, id, bs);
// Peer coord will get metadata from MagnetState,
// verify, and then call gotMetaInfo()
@@ -519,10 +526,14 @@ class PeerState implements DataLoader
setInteresting(true);
}
/** @since 0.8.4 */
/**
* Unused
* @since 0.8.4
*/
void portMessage(int port)
{
listener.gotPort(peer, port);
// for compatibility with old DHT PORT message
listener.gotPort(peer, port, port + 1);
}
void unknownMessage(int type, byte[] bs)
@@ -567,19 +578,20 @@ class PeerState implements DataLoader
* @since 0.8.1
*/
synchronized void cancelPiece(int piece) {
if (lastRequest != null && lastRequest.piece == piece)
if (lastRequest != null && lastRequest.getPiece() == piece)
lastRequest = null;
Iterator<Request> it = outstandingRequests.iterator();
while (it.hasNext())
{
Request req = it.next();
if (req.piece == piece)
if (req.getPiece() == piece)
{
it.remove();
// Send cancel even when we are choked to make sure that it is
// really never ever send.
out.sendCancel(req);
req.getPartialPiece().release();
}
}
}
@@ -590,10 +602,10 @@ class PeerState implements DataLoader
* @since 0.8.1
*/
synchronized boolean isRequesting(int piece) {
if (pendingRequest != null && pendingRequest.piece == piece)
if (pendingRequest != null && pendingRequest.getPiece() == piece)
return true;
for (Request req : outstandingRequests) {
if (req.piece == piece)
if (req.getPiece() == piece)
return true;
}
return false;
@@ -670,12 +682,13 @@ 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
{
int pieceLength;
boolean isLastChunk;
pieceLength = metainfo.getPieceLength(lastRequest.piece);
pieceLength = metainfo.getPieceLength(lastRequest.getPiece());
isLastChunk = lastRequest.off + lastRequest.len == pieceLength;
// Last part of a piece?
@@ -683,14 +696,13 @@ class PeerState implements DataLoader
more_pieces = requestNextPiece();
else
{
int nextPiece = lastRequest.piece;
PartialPiece nextPiece = lastRequest.getPartialPiece();
int nextBegin = lastRequest.off + PARTSIZE;
byte[] bs = lastRequest.bs;
int maxLength = pieceLength - nextBegin;
int nextLength = maxLength > PARTSIZE ? PARTSIZE
: maxLength;
Request req
= new Request(nextPiece, bs, nextBegin, nextLength);
= new Request(nextPiece,nextBegin, nextLength);
outstandingRequests.add(req);
if (!choked)
out.sendRequest(req);
@@ -700,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);
@@ -727,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();
}
}
@@ -736,7 +754,7 @@ class PeerState implements DataLoader
// what piece to give us next.
int nextPiece = listener.wantPiece(peer, bitfield);
if (nextPiece != -1
&& (lastRequest == null || lastRequest.piece != nextPiece)) {
&& (lastRequest == null || lastRequest.getPiece() != nextPiece)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug(peer + " want piece " + nextPiece);
// Fail safe to make sure we are interested
@@ -773,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,9 +54,21 @@ 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()); }
/**
* How many peers have this piece?
* Caller must synchronize
* @since 0.9.1
*/
public int getPeerCount() {
return this.peers.size();
}
/** caller must synchronize */
public boolean isRequested() {
return this.requests != null && !this.requests.isEmpty();
@@ -95,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

@@ -20,14 +20,16 @@
package org.klomp.snark;
import java.io.DataInputStream;
import java.io.IOException;
/**
* Holds all information needed for a partial piece request.
* This class should be used only by PeerState, PeerConnectionIn, and PeerConnectionOut.
*/
class Request
{
final int piece;
final byte[] bs;
private final PartialPiece piece;
final int off;
final int len;
long sendTime;
@@ -36,26 +38,49 @@ class Request
* Creates a new Request.
*
* @param piece Piece number requested.
* @param bs byte array where response should be stored.
* @param off the offset in the array.
* @param len the number of bytes requested.
*/
Request(int piece, byte[] bs, int off, int len)
Request(PartialPiece piece, int off, int len)
{
// Sanity check
if (off < 0 || len <= 0 || off + len > piece.getLength())
throw new IndexOutOfBoundsException("Illegal Request " + toString());
this.piece = piece;
this.bs = bs;
this.off = off;
this.len = len;
}
// Sanity check
if (piece < 0 || off < 0 || len <= 0 || off + len > bs.length)
throw new IndexOutOfBoundsException("Illegal Request " + toString());
/**
* @since 0.9.1
*/
public void read(DataInputStream din) throws IOException {
piece.read(din, off, len);
}
/**
* The piece number this Request is for
*
* @since 0.9.1
*/
public int getPiece() {
return piece.getPiece();
}
/**
* The PartialPiece this Request is for
*
* @since 0.9.1
*/
public PartialPiece getPartialPiece() {
return piece;
}
@Override
public int hashCode()
{
return piece ^ off ^ len;
return piece.getPiece() ^ off ^ len;
}
@Override
@@ -64,7 +89,7 @@ class Request
if (o instanceof Request)
{
Request req = (Request)o;
return req.piece == piece && req.off == off && req.len == len;
return req.piece.equals(piece) && req.off == off && req.len == len;
}
return false;
@@ -73,6 +98,6 @@ class Request
@Override
public String toString()
{
return "(" + piece + "," + off + "," + len + ")";
return "(" + piece.getPiece() + "," + off + "," + len + ")";
}
}

View File

@@ -20,12 +20,10 @@
package org.klomp.snark;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -37,6 +35,7 @@ import net.i2p.I2PAppContext;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.data.Destination;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
/**
* Main Snark program startup class.
@@ -49,34 +48,12 @@ public class Snark
private final static int MIN_PORT = 6881;
private final static int MAX_PORT = 6889;
// Error messages (non-fatal)
public final static int ERROR = 1;
// Warning messages
public final static int WARNING = 2;
// Notices (peer level)
public final static int NOTICE = 3;
// Info messages (protocol policy level)
public final static int INFO = 4;
// Debug info (protocol level)
public final static int DEBUG = 5;
// Very low level stuff (network level)
public final static int ALL = 6;
/**
* What level of debug info to show.
*/
//public static int debug = NOTICE;
// Whether or not to ask the user for commands while sharing
private static boolean command_interpreter = true;
//private static boolean command_interpreter = true;
private static final String newline = System.getProperty("line.separator");
/****
private static final String copyright =
"The Hunting of the Snark Project - Copyright (C) 2003 Mark J. Wielaard"
+ newline + newline
@@ -92,10 +69,12 @@ public class Snark
"Press return for help. Type \"quit\" and return to stop.";
private static final String help =
"Commands: 'info', 'list', 'quit'.";
****/
// String indicating main activity
String activity = "Not started";
/****
private static class OOMListener implements I2PThread.OOMEventListener {
public void outOfMemory(OutOfMemoryError err) {
try {
@@ -108,6 +87,7 @@ public class Snark
}
}
****/
/******** No, not maintaining a command-line client
@@ -247,11 +227,13 @@ public class Snark
private TrackerClient trackerclient;
private String rootDataDir = ".";
private final CompleteListener completeListener;
private boolean stopped;
private volatile boolean stopped;
private volatile boolean starting;
private byte[] id;
private byte[] infoHash;
private final byte[] infoHash;
private String additionalTrackerURL;
private final I2PSnarkUtil _util;
private final Log _log;
private final PeerCoordinatorSet _peerCoordinatorSet;
private String trackerProblems;
private int trackerSeenPeers;
@@ -305,6 +287,7 @@ public class Snark
completeListener = complistener;
_util = util;
_log = util.getContext().logManager().getLog(Snark.class);
_peerCoordinatorSet = peerCoordinatorSet;
acceptor = connectionAcceptor;
@@ -315,10 +298,9 @@ public class Snark
activity = "Network setup";
id = generateID();
debug("My peer id: " + PeerID.idencode(id), Snark.INFO);
if (_log.shouldLog(Log.INFO))
_log.info("My peer id: " + PeerID.idencode(id));
int port;
IOException lastException = null;
/*
* Don't start a tunnel if the torrent isn't going to be started.
* If we are starting,
@@ -339,6 +321,7 @@ public class Snark
meta = null;
File f = null;
InputStream in = null;
byte[] x_infoHash = null;
try
{
f = new File(torrent);
@@ -346,6 +329,8 @@ public class Snark
in = new FileInputStream(f);
else
{
/**** No, we don't ever fetch a torrent file this way
and we don't want to block in the constructor
activity = "Getting torrent";
File torrentFile = _util.get(torrent, 3);
if (torrentFile == null) {
@@ -355,9 +340,11 @@ public class Snark
torrentFile.deleteOnExit();
in = new FileInputStream(torrentFile);
}
*****/
throw new IOException("not found");
}
meta = new MetaInfo(in);
infoHash = meta.getInfoHash();
x_infoHash = meta.getInfoHash();
}
catch(IOException ioe)
{
@@ -398,7 +385,9 @@ public class Snark
try { in.close(); } catch (IOException ioe) {}
}
debug(meta.toString(), INFO);
infoHash = x_infoHash; // final
if (_log.shouldLog(Log.INFO))
_log.info(meta.toString());
// When the metainfo torrent was created from an existing file/dir
// it already exists.
@@ -459,6 +448,7 @@ public class Snark
{
completeListener = complistener;
_util = util;
_log = util.getContext().logManager().getLog(Snark.class);
_peerCoordinatorSet = peerCoordinatorSet;
acceptor = connectionAcceptor;
this.torrent = torrent;
@@ -505,9 +495,19 @@ public class Snark
}
/**
* Start up contacting peers and querying the tracker
* Start up contacting peers and querying the tracker.
* Blocks if tunnel is not yet open.
*/
public void startTorrent() {
public synchronized void startTorrent() {
starting = true;
try {
x_startTorrent();
} finally {
starting = false;
}
}
private void x_startTorrent() {
boolean ok = _util.connect();
if (!ok) fatal("Unable to connect to I2P");
if (coordinator == null) {
@@ -516,9 +516,11 @@ public class Snark
fatal("Unable to listen for I2P connections");
else {
Destination d = serversocket.getManager().getSession().getMyDestination();
debug("Listening on I2P destination " + d.toBase64() + " / " + d.calculateHash().toBase64(), NOTICE);
if (_log.shouldLog(Log.INFO))
_log.info("Listening on I2P destination " + d.toBase64() + " / " + d.calculateHash().toBase64());
}
debug("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient", NOTICE);
if (_log.shouldLog(Log.INFO))
_log.info("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient");
activity = "Collecting pieces";
coordinator = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this);
if (_peerCoordinatorSet != null) {
@@ -538,21 +540,14 @@ public class Snark
}
stopped = false;
boolean coordinatorChanged = false;
if (coordinator.halted()) {
// ok, we have already started and stopped, but the coordinator seems a bit annoying to
// restart safely, so lets build a new one to replace the old
coordinator.restart();
if (_peerCoordinatorSet != null)
_peerCoordinatorSet.remove(coordinator);
PeerCoordinator newCoord = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this);
if (_peerCoordinatorSet != null)
_peerCoordinatorSet.add(newCoord);
coordinator = newCoord;
coordinatorChanged = true;
_peerCoordinatorSet.add(coordinator);
}
if (!trackerclient.started() && !coordinatorChanged) {
if (!trackerclient.started()) {
trackerclient.start();
} else if (trackerclient.halted() || coordinatorChanged) {
} else if (trackerclient.halted()) {
if (storage != null) {
try {
storage.reopen(rootDataDir);
@@ -563,23 +558,30 @@ public class Snark
fatal("Could not reopen storage", ioe);
}
}
TrackerClient newClient = new TrackerClient(_util, meta, additionalTrackerURL, coordinator, this);
if (!trackerclient.halted())
trackerclient.halt();
trackerclient = newClient;
trackerclient.start();
} else {
debug("NOT starting TrackerClient???", NOTICE);
if (_log.shouldLog(Log.INFO))
_log.info("NOT starting TrackerClient???");
}
}
/**
* Stop contacting the tracker and talking with peers
*/
public void stopTorrent() {
stopTorrent(false);
}
/**
* Stop contacting the tracker and talking with peers
* @param fast if true, limit the life of the unannounce threads
* @since 0.9.1
*/
public synchronized void stopTorrent(boolean fast) {
stopped = true;
TrackerClient tc = trackerclient;
if (tc != null)
tc.halt();
tc.halt(fast);
PeerCoordinator pc = coordinator;
if (pc != null)
pc.halt();
@@ -601,10 +603,12 @@ public class Snark
_util.disconnect();
}
/****
private static Snark parseArguments(String[] args)
{
return parseArguments(args, null, null);
}
****/
// Accessors
@@ -668,6 +672,38 @@ public class Snark
return stopped;
}
/**
* Startup in progress.
* @since 0.9.1
*/
public boolean isStarting() {
return starting && stopped;
}
/**
* Set startup in progress.
* @since 0.9.1
*/
public void setStarting() {
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
*/
@@ -780,6 +816,7 @@ public class Snark
}
/**
* Bytes not yet in storage. Does NOT account for skipped files.
* @return exact value. or -1 if no storage yet.
* getNeeded() * pieceLength(0) isn't accurate if last piece
* is still needed.
@@ -800,6 +837,20 @@ public class Snark
}
/**
* Bytes still wanted. DOES account for skipped files.
* FIXME -1 when not running.
* @return exact value. or -1 if no storage yet or when not running.
* @since 0.9.1
*/
public long getNeededLength() {
PeerCoordinator coord = coordinator;
if (coord != null)
return coord.getNeededLength();
return -1;
}
/**
* Does not account for skipped files.
* @return number of pieces still needed (magnet mode or not), or -1 if unknown
* @since 0.8.4
*/
@@ -911,7 +962,7 @@ public class Snark
}
else if (args[i].equals("--no-commands"))
{
command_interpreter = false;
//command_interpreter = false;
i++;
}
//else if (args[i].equals("--eepproxy"))
@@ -970,22 +1021,13 @@ public class Snark
private static void usage()
{
System.out.println
("Usage: snark [--debug [level]] [--no-commands] [--port <port>]");
("Usage: snark [--no-commands] [--port <port>]");
System.out.println
(" [--eepproxy hostname portnum]");
System.out.println
(" [--i2cp routerHost routerPort ['name=val name=val name=val']]");
System.out.println
(" (<url>|<file>)");
System.out.println
(" --debug\tShows some extra info and stacktraces");
System.out.println
(" level\tHow much debug details to show");
System.out.println
(" \t(defaults to "
+ NOTICE + ", with --debug to "
+ INFO + ", highest level is "
+ ALL + ").");
System.out.println
(" --no-commands\tDon't read interactive commands or show usage info.");
System.out.println
@@ -1024,22 +1066,18 @@ public class Snark
*/
private void fatal(String s, Throwable t)
{
_util.debug(s, ERROR, t);
_log.error(s, t);
//System.err.println("snark: " + s + ((t == null) ? "" : (": " + t)));
//if (debug >= INFO && t != null)
// t.printStackTrace();
stopTorrent();
if (t != null)
s += ": " + t;
if (completeListener != null)
completeListener.fatal(this, s);
throw new RuntimeException(s, t);
}
/**
* Show debug info if debug is true.
*/
private void debug(String s, int level)
{
_util.debug(s, level, null);
}
/** CoordinatorListener - this does nothing */
public void peerChange(PeerCoordinator coordinator, Peer peer)
{
@@ -1056,10 +1094,12 @@ public class Snark
* @since 0.8.4
*/
public void gotMetaInfo(PeerCoordinator coordinator, MetaInfo metainfo) {
meta = metainfo;
try {
storage = new Storage(_util, meta, this);
// The following two may throw IOE...
storage = new Storage(_util, metainfo, this);
storage.check(rootDataDir);
// ... so don't set meta until here
meta = metainfo;
if (completeListener != null) {
String newName = completeListener.gotMetaInfo(this);
if (newName != null)
@@ -1075,7 +1115,12 @@ public class Snark
}
}
private boolean allocating = false;
///////////// Begin StorageListener methods
//private boolean allocating = false;
/** does nothing */
public void storageCreateFile(Storage storage, String name, long length)
{
//if (allocating)
@@ -1083,27 +1128,29 @@ public class Snark
//System.out.print("Creating file '" + name
// + "' of length " + length + ": ");
allocating = true;
//allocating = true;
}
// How much storage space has been allocated
private long allocated = 0;
/** does nothing */
public void storageAllocated(Storage storage, long length)
{
allocating = true;
//allocating = true;
//System.out.print(".");
allocated += length;
//allocated += length;
//if (allocated == meta.getTotalLength())
// System.out.println(); // We have all the disk space we need.
}
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;
//allocating = false;
if (!allChecked && !checking)
{
// Use the MetaInfo from the storage since our own might not
@@ -1115,9 +1162,12 @@ public class Snark
// + " pieces: ");
checking = true;
}
if (!checking)
debug("Got " + (checked ? "" : "BAD ") + "piece: " + num,
Snark.INFO);
if (!checking) {
if (_log.shouldLog(Log.INFO))
_log.info("Got " + (checked ? "" : "BAD ") + "piece: " + num);
if (completeListener != null)
completeListener.gotPiece(this);
}
}
public void storageAllChecked(Storage storage)
@@ -1133,7 +1183,8 @@ public class Snark
public void storageCompleted(Storage storage)
{
debug("Completely received " + torrent, Snark.INFO);
if (_log.shouldLog(Log.INFO))
_log.info("Completely received " + torrent);
//storage.close();
//System.out.println("Completely received: " + torrent);
if (completeListener != null)
@@ -1145,6 +1196,9 @@ public class Snark
coordinator.setWantedPieces();
}
///////////// End StorageListener methods
/** SnarkSnutdown callback unused */
public void shutdown()
{
@@ -1153,25 +1207,16 @@ public class Snark
//System.exit(0);
}
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);
// not really listeners but the easiest way to get back to an optional SnarkManager
public long getSavedTorrentTime(Snark snark);
public BitField getSavedTorrentBitField(Snark snark);
/**
* StorageListener and CoordinatorListener callback
* @since 0.9.2
*/
public void addMessage(String message) {
if (completeListener != null)
completeListener.addMessage(this, message);
}
/** Maintain a configurable total uploader cap
* coordinatorListener
*/
@@ -1181,8 +1226,8 @@ public class Snark
if (_peerCoordinatorSet == null || uploaders <= 0)
return false;
int totalUploaders = 0;
for (Iterator iter = _peerCoordinatorSet.iterator(); iter.hasNext(); ) {
PeerCoordinator c = (PeerCoordinator)iter.next();
for (Iterator<PeerCoordinator> iter = _peerCoordinatorSet.iterator(); iter.hasNext(); ) {
PeerCoordinator c = iter.next();
if (!c.halted())
totalUploaders += c.uploaders;
}
@@ -1195,13 +1240,14 @@ public class Snark
if (_peerCoordinatorSet == null)
return false;
long total = 0;
for (Iterator iter = _peerCoordinatorSet.iterator(); iter.hasNext(); ) {
PeerCoordinator c = (PeerCoordinator)iter.next();
for (Iterator<PeerCoordinator> iter = _peerCoordinatorSet.iterator(); iter.hasNext(); ) {
PeerCoordinator c = iter.next();
if (!c.halted())
total += c.getCurrentUploadRate();
}
long limit = 1024l * _util.getMaxUpBW();
debug("Total up bw: " + total + " Limit: " + limit, Snark.WARNING);
if (_log.shouldLog(Log.INFO))
_log.info("Total up bw: " + total + " Limit: " + limit);
return total > limit;
}

View File

@@ -8,6 +8,10 @@ import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -16,13 +20,14 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.Collection;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
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;
@@ -30,13 +35,15 @@ import net.i2p.util.Log;
import net.i2p.util.OrderedProperties;
import net.i2p.util.SecureDirectory;
import net.i2p.util.SecureFileOutputStream;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer;
import org.klomp.snark.dht.DHT;
/**
* Manage multiple snarks
*/
public class SnarkManager implements Snark.CompleteListener {
private static SnarkManager _instance = new SnarkManager();
public static SnarkManager instance() { return _instance; }
public class SnarkManager implements CompleteListener {
/**
* Map of (canonical) filename of the .torrent file to Snark instance.
@@ -51,12 +58,16 @@ public class SnarkManager implements Snark.CompleteListener {
private Properties _config;
private final I2PAppContext _context;
private final Log _log;
private final List _messages;
private final Queue<String> _messages;
private final I2PSnarkUtil _util;
private PeerCoordinatorSet _peerCoordinatorSet;
private ConnectionAcceptor _connectionAcceptor;
private Thread _monitor;
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,27 +90,56 @@ 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 RC_PROP_THEME = "routerconsole.theme";
public static final String RC_PROP_UNIVERSAL_THEMING = "routerconsole.universal.theme";
public static final String PROP_THEME = "i2psnark.theme";
public static final String DEFAULT_THEME = "ubergine";
private static final String PROP_USE_OPENTRACKERS = "i2psnark.useOpentrackers";
public static final String PROP_OPENTRACKERS = "i2psnark.opentrackers";
public static final String PROP_PRIVATETRACKERS = "i2psnark.privatetrackers";
private static final String PROP_USE_DHT = "i2psnark.enableDHT";
public static final int MIN_UP_BW = 2;
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 SnarkManager() {
/**
* "name", "announceURL=websiteURL" pairs
* '=' in announceURL must be escaped as &#44;
*/
public static final String DEFAULT_TRACKERS[] = {
// "Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/"
// , "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/"
// , "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/"
// , "NickyB", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php=http://nickyb.i2p/bittorrent/"
// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/"
// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/"
// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php"
// , "mastertracker", "http://VzXD~stRKbL3MOmeTn1iaCQ0CFyTmuFHiKYyo0Rd~dFPZFCYH-22rT8JD7i-C2xzYFa4jT5U2aqHzHI-Jre4HL3Ri5hFtZrLk2ax3ji7Qfb6qPnuYkuiF2E2UDmKUOppI8d9Ye7tjdhQVCy0izn55tBaB-U7UWdcvSK2i85sauyw3G0Gfads1Rvy5-CAe2paqyYATcDmGjpUNLoxbfv9KH1KmwRTNH6k1v4PyWYYnhbT39WfKMbBjSxVQRdi19cyJrULSWhjxaQfJHeWx5Z8Ev4bSPByBeQBFl2~4vqy0S5RypINsRSa3MZdbiAAyn5tr5slWR6QdoqY3qBQgBJFZppy-3iWkFqqKgSxCPundF8gdDLC5ddizl~KYcYKl42y9SGFHIukH-TZs8~em0~iahzsqWVRks3zRG~tlBcX2U3M2~OJs~C33-NKhyfZT7-XFBREvb8Szmd~p66jDxrwOnKaku-G6DyoQipJqIz4VHmY9-y5T8RrUcJcM-5lVoMpAAAA.i2p/announce.php=http://tracker.mastertracker.i2p/"
// , "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/"
// , "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/"
};
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
public static final String PROP_TRACKERS = "i2psnark.trackers";
public SnarkManager(I2PAppContext ctx) {
_snarks = new ConcurrentHashMap();
_magnets = new ConcurrentHashSet();
_addSnarkLock = new Object();
_context = I2PAppContext.getGlobalContext();
_context = ctx;
_log = _context.logManager().getLog(SnarkManager.class);
_messages = new ArrayList(16);
_messages = new LinkedBlockingQueue();
_util = new I2PSnarkUtil(_context);
_configFile = new File(CONFIG_FILE);
if (!_configFile.isAbsolute())
_configFile = new File(_context.getConfigDir(), CONFIG_FILE);
_trackerMap = new ConcurrentHashMap(4);
loadConfig(null);
}
@@ -112,35 +152,72 @@ public class SnarkManager implements Snark.CompleteListener {
_connectionAcceptor = new ConnectionAcceptor(_util);
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
_monitor.start();
_context.addShutdownTask(new SnarkManagerShutdown());
// 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.
* Fix this so an individual webaapp stop will close the tunnel.
* 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();
(new SnarkManagerShutdown()).run();
stopAllTorrents(true);
}
/** @since 0.9.1 */
public boolean isStopping() { return _stopping; }
/** hook to I2PSnarkUtil for the servlet */
public I2PSnarkUtil util() { return _util; }
private static final int MAX_MESSAGES = 5;
private static final int MAX_MESSAGES = 100;
public void addMessage(String message) {
synchronized (_messages) {
_messages.add(message);
while (_messages.size() > MAX_MESSAGES)
_messages.remove(0);
_messages.offer(message);
while (_messages.size() > MAX_MESSAGES) {
_messages.poll();
}
if (_log.shouldLog(Log.INFO))
_log.info("MSG: " + message);
}
/** newest last */
public List getMessages() {
synchronized (_messages) {
return new ArrayList(_messages);
}
public List<String> getMessages() {
if (_messages.isEmpty())
return Collections.EMPTY_LIST;
return new ArrayList(_messages);
}
/** @since 0.9 */
public void clearMessages() {
_messages.clear();
}
/**
@@ -148,11 +225,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));
}
/****
@@ -237,6 +314,9 @@ public class SnarkManager implements Snark.CompleteListener {
_config.setProperty(PROP_STARTUP_DELAY, Integer.toString(DEFAULT_STARTUP_DELAY));
if (!_config.containsKey(PROP_THEME))
_config.setProperty(PROP_THEME, DEFAULT_THEME);
// no, so we can switch default to true later
//if (!_config.containsKey(PROP_USE_DHT))
// _config.setProperty(PROP_USE_DHT, Boolean.toString(I2PSnarkUtil.DEFAULT_USE_DHT));
updateConfig();
}
/**
@@ -245,6 +325,26 @@ public class SnarkManager implements Snark.CompleteListener {
*/
public String getTheme() {
String theme = _config.getProperty(PROP_THEME);
boolean universalTheming = _context.getBooleanProperty(RC_PROP_UNIVERSAL_THEMING);
if (universalTheming) {
// Fetch routerconsole theme (or use our default if it doesn't exist)
theme = _context.getProperty(RC_PROP_THEME, DEFAULT_THEME);
// Ensure that theme exists
String[] themes = getThemes();
boolean themeExists = false;
for (int i = 0; i < themes.length; i++) {
if (themes[i].equals(theme))
themeExists = true;
}
if (!themeExists) {
// Since the default is not "light", explicitly check if universal theme is "classic"
if (theme.equals("classic"))
theme = "light";
else
theme = DEFAULT_THEME;
_config.setProperty(PROP_THEME, DEFAULT_THEME);
}
}
return theme;
}
@@ -307,11 +407,15 @@ public class SnarkManager implements Snark.CompleteListener {
_util.setFilesPublic(areFilesPublic());
String ot = _config.getProperty(PROP_OPENTRACKERS);
if (ot != null)
_util.setOpenTrackerString(ot);
_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.parseBoolean(_config.getProperty(PROP_USE_DHT,
Boolean.toString(I2PSnarkUtil.DEFAULT_USE_DHT))));
getDataDir().mkdirs();
initTrackerMap();
}
private int getInt(String prop, int defaultVal) {
@@ -328,7 +432,7 @@ public class SnarkManager implements Snark.CompleteListener {
public void updateConfig(String dataDir, boolean filesPublic, boolean autoStart, String refreshDelay,
String startDelay, String seedPct, String eepHost,
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
String upLimit, String upBW, boolean useOpenTrackers, String openTrackers, String theme) {
String upLimit, String upBW, boolean useOpenTrackers, boolean useDHT, String theme) {
boolean changed = false;
//if (eepHost != null) {
// // unused, we use socket eepget
@@ -512,13 +616,16 @@ public class SnarkManager implements Snark.CompleteListener {
_util.setUseOpenTrackers(useOpenTrackers);
changed = true;
}
if (openTrackers != null) {
if (openTrackers.trim().length() > 0 && !openTrackers.trim().equals(_util.getOpenTrackerString())) {
_config.setProperty(PROP_OPENTRACKERS, openTrackers.trim());
_util.setOpenTrackerString(openTrackers);
addMessage(_("Open Tracker list changed - torrent restart required to take effect."));
changed = true;
}
if (_util.shouldUseDHT() != useDHT) {
_config.setProperty(PROP_USE_DHT, Boolean.toString(useDHT));
if (useDHT)
addMessage(_("Enabled DHT."));
else
addMessage(_("Disabled DHT."));
if (_util.connected())
addMessage(_("DHT change requires tunnel shutdown and reopen"));
_util.setUseDHT(useDHT);
changed = true;
}
if (theme != null) {
if(!theme.equals(_config.getProperty(PROP_THEME))) {
@@ -534,6 +641,84 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
/**
* Others should use the version in I2PSnarkUtil
* @return non-null, empty if disabled
* @since 0.9.1
*/
private List<String> getOpenTrackers() {
if (!_util.shouldUseOpenTrackers())
return Collections.EMPTY_LIST;
return getListConfig(PROP_OPENTRACKERS, I2PSnarkUtil.DEFAULT_OPENTRACKERS);
}
/**
* @return non-null, fixed size, may be empty or unmodifiable
* @since 0.9.1
*/
public List<String> getPrivateTrackers() {
return getListConfig(PROP_PRIVATETRACKERS, null);
}
/**
* @param ot null to restore default
* @since 0.9.1
*/
public void saveOpenTrackers(List<String> ot) {
String val = setListConfig(PROP_OPENTRACKERS, ot);
if (ot == null)
ot = Collections.singletonList(I2PSnarkUtil.DEFAULT_OPENTRACKERS);
_util.setOpenTrackers(ot);
addMessage(_("Open Tracker list changed - torrent restart required to take effect."));
saveConfig();
}
/**
* @param pt null ok, default is none
* @since 0.9.1
*/
public void savePrivateTrackers(List<String> pt) {
setListConfig(PROP_PRIVATETRACKERS, pt);
addMessage(_("Private tracker list changed - affects newly created torrents only."));
saveConfig();
}
/**
* @param dflt default or null
* @return non-null, fixed size
* @since 0.9.1
*/
private List<String> getListConfig(String prop, String dflt) {
String val = _config.getProperty(prop);
if (val == null)
val = dflt;
if (val == null)
return Collections.EMPTY_LIST;
return Arrays.asList(val.split(","));
}
/**
* Sets the config, does NOT save it
* @param values may be null or empty
* @return the comma-separated config string, non-null
* @since 0.9.1
*/
private String setListConfig(String prop, List<String> values) {
if (values == null || values.isEmpty()) {
_config.remove(prop);
return "";
}
StringBuilder buf = new StringBuilder(64);
for (String s : values) {
if (buf.length() > 0)
buf.append(',');
buf.append(s);
}
String rv = buf.toString();
_config.setProperty(prop, rv);
return rv;
}
public void saveConfig() {
try {
synchronized (_configFile) {
@@ -547,7 +732,7 @@ public class SnarkManager implements Snark.CompleteListener {
public Properties getConfig() { return _config; }
/** 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.
@@ -563,6 +748,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
@@ -623,7 +816,7 @@ public class SnarkManager implements Snark.CompleteListener {
File dataDir = getDataDir();
Snark torrent = null;
synchronized (_snarks) {
torrent = (Snark)_snarks.get(filename);
torrent = _snarks.get(filename);
}
// don't hold the _snarks lock while verifying the torrent
if (torrent == null) {
@@ -663,14 +856,16 @@ public class SnarkManager implements Snark.CompleteListener {
}
if (!TrackerClient.isValidAnnounce(info.getAnnounce())) {
if (_util.shouldUseOpenTrackers() && _util.getOpenTrackers() != null) {
//addMessage(_("Warning - No I2P trackers in \"{0}\", will announce to I2P open trackers and DHT only.", info.getName()));
addMessage(_("Warning - No I2P trackers in \"{0}\", will announce to I2P open trackers only.", info.getName()));
//} else if (_util.getDHT() != null) {
// addMessage(_("Warning - No I2P trackers in \"{0}\", and open trackers are disabled, will announce to DHT only.", info.getName()));
if (info.isPrivate()) {
addMessage(_("ERROR - No I2P trackers in private torrent \"{0}\"", info.getName()));
} else if (!_util.getOpenTrackers().isEmpty()) {
addMessage(_("Warning - No I2P trackers in \"{0}\", will announce to I2P open trackers and DHT only.", info.getName()));
//addMessage(_("Warning - No I2P trackers in \"{0}\", will announce to I2P open trackers only.", info.getName()));
} else if (_util.shouldUseDHT()) {
addMessage(_("Warning - No I2P trackers in \"{0}\", and open trackers are disabled, will announce to DHT only.", info.getName()));
} else {
//addMessage(_("Warning - No I2P trackers in \"{0}\", and DHT and open trackers are disabled, you should enable open trackers or DHT before starting the torrent.", info.getName()));
addMessage(_("Warning - No I2P Trackers found in \"{0}\". Make sure Open Tracker is enabled before starting this torrent.", info.getName()));
addMessage(_("Warning - No I2P trackers in \"{0}\", and DHT and open trackers are disabled, you should enable open trackers or DHT before starting the torrent.", info.getName()));
//addMessage(_("Warning - No I2P Trackers found in \"{0}\". Make sure Open Tracker is enabled before starting this torrent.", info.getName()));
dontAutoStart = true;
}
}
@@ -727,7 +922,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());
@@ -735,7 +950,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);
@@ -743,17 +958,21 @@ public class SnarkManager implements Snark.CompleteListener {
saveMagnetStatus(ih);
_snarks.put(name, torrent);
}
if (shouldAutoStart()) {
torrent.startTorrent();
if (autoStart) {
startTorrent(ih);
addMessage(_("Fetching {0}", name));
boolean haveSavedPeers = false;
if ((!util().connected()) && !haveSavedPeers) {
addMessage(_("We have no saved peers and no other torrents are running. " +
"Fetch of {0} will not succeed until you start another torrent.", name));
DHT dht = _util.getDHT();
boolean shouldWarn = _util.connected() &&
_util.getOpenTrackers().isEmpty() &&
((!_util.shouldUseDHT()) || dht == null || dht.size() <= 0);
if (shouldWarn) {
addMessage(_("Open trackers are disabled and we have no DHT peers. " +
"Fetch of {0} may not succeed until you start another torrent, enable open trackers, or enable DHT.", name));
}
} else {
addMessage(_("Adding {0}", name));
}
}
return torrent;
}
/**
@@ -770,6 +989,29 @@ public class SnarkManager implements Snark.CompleteListener {
_magnets.remove(snark.getName());
removeMagnetStatus(snark.getInfoHash());
}
/**
* Add and start a FetchAndAdd task.
* Remove it with deleteMagnet().
*
* @param torrent must be instanceof FetchAndAdd
* @throws RuntimeException via Snark.fatal()?
* @since 0.9.1
*/
public void addDownloader(Snark torrent) {
synchronized (_snarks) {
Snark snark = getTorrentByInfoHash(torrent.getInfoHash());
if (snark != null) {
addMessage(_("Download already running: {0}", snark.getBaseName()));
return;
}
String name = torrent.getName();
// Tell the dir monitor not to delete us
_magnets.add(name);
_snarks.put(name, torrent);
}
torrent.startTorrent();
}
/**
* Add a torrent from a MetaInfo. Save the MetaInfo data to filename.
@@ -1091,9 +1333,9 @@ public class SnarkManager implements Snark.CompleteListener {
Snark torrent = null;
synchronized (_snarks) {
if (shouldRemove)
torrent = (Snark)_snarks.remove(filename);
torrent = _snarks.remove(filename);
else
torrent = (Snark)_snarks.get(filename);
torrent = _snarks.get(filename);
remaining = _snarks.size();
}
if (torrent != null) {
@@ -1152,13 +1394,11 @@ public class SnarkManager implements Snark.CompleteListener {
// don't bother delaying if auto start is false
long delay = 60 * 1000 * getStartupDelayMinutes();
if (delay > 0 && shouldAutoStart()) {
_messages.add(_("Adding torrents in {0}", DataHelper.formatDuration2(delay)));
addMessage(_("Adding torrents in {0}", DataHelper.formatDuration2(delay)));
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
// the first message was a "We are starting up in 1m"
synchronized (_messages) {
if (_messages.size() == 1)
_messages.remove(0);
}
// Remove that first message
if (_messages.size() == 1)
_messages.poll();
}
// here because we need to delay until I2CP is up
@@ -1184,6 +1424,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) {}
}
@@ -1239,8 +1481,11 @@ public class SnarkManager implements Snark.CompleteListener {
return null;
}
saveTorrentStatus(meta, storage.getBitField(), null); // no file priorities
String name = (new File(getDataDir(), storage.getBaseName() + ".torrent")).getAbsolutePath();
// temp for addMessage() in case canonical throws
String name = storage.getBaseName();
try {
// _snarks must use canonical
name = (new File(getDataDir(), storage.getBaseName() + ".torrent")).getCanonicalPath();
// put the announce URL in the file
String announce = snark.getTrackerURL();
if (announce != null)
@@ -1264,6 +1509,28 @@ public class SnarkManager implements Snark.CompleteListener {
return null;
}
/**
* A Snark.CompleteListener method.
* @since 0.9
*/
public void fatal(Snark snark, String error) {
addMessage(_("Error on torrent {0}", snark.getName()) + ": " + error);
}
/**
* A Snark.CompleteListener method.
* @since 0.9.2
*/
public void addMessage(Snark snark, String message) {
addMessage(message);
}
/**
* A Snark.CompleteListener method.
* @since 0.9.4
*/
public void gotPiece(Snark snark) {}
// End Snark.CompleteListeners
/**
@@ -1279,7 +1546,7 @@ public class SnarkManager implements Snark.CompleteListener {
byte[] ih = Base64.decode(b64);
// ignore value - TODO put tracker URL in value
if (ih != null && ih.length == 20)
addMagnet("Magnet: " + I2PSnarkUtil.toHex(ih), ih, null, false);
addMagnet(_("Magnet") + ' ' + I2PSnarkUtil.toHex(ih), ih, null, false);
// else remove from config?
}
}
@@ -1356,57 +1623,89 @@ public class SnarkManager implements Snark.CompleteListener {
}
/**
* "name", "announceURL=websiteURL" pairs
* Unsorted map of name to Tracker object
* Modifiable, not a copy
* @since 0.9.1
*/
private static final String DEFAULT_TRACKERS[] = {
// "Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/"
// , "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/"
// , "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/"
// , "NickyB", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php=http://nickyb.i2p/bittorrent/"
// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/"
// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/"
// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php"
// , "mastertracker", "http://VzXD~stRKbL3MOmeTn1iaCQ0CFyTmuFHiKYyo0Rd~dFPZFCYH-22rT8JD7i-C2xzYFa4jT5U2aqHzHI-Jre4HL3Ri5hFtZrLk2ax3ji7Qfb6qPnuYkuiF2E2UDmKUOppI8d9Ye7tjdhQVCy0izn55tBaB-U7UWdcvSK2i85sauyw3G0Gfads1Rvy5-CAe2paqyYATcDmGjpUNLoxbfv9KH1KmwRTNH6k1v4PyWYYnhbT39WfKMbBjSxVQRdi19cyJrULSWhjxaQfJHeWx5Z8Ev4bSPByBeQBFl2~4vqy0S5RypINsRSa3MZdbiAAyn5tr5slWR6QdoqY3qBQgBJFZppy-3iWkFqqKgSxCPundF8gdDLC5ddizl~KYcYKl42y9SGFHIukH-TZs8~em0~iahzsqWVRks3zRG~tlBcX2U3M2~OJs~C33-NKhyfZT7-XFBREvb8Szmd~p66jDxrwOnKaku-G6DyoQipJqIz4VHmY9-y5T8RrUcJcM-5lVoMpAAAA.i2p/announce.php=http://tracker.mastertracker.i2p/"
// , "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/"
// , "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/"
};
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
public static final String PROP_TRACKERS = "i2psnark.trackers";
private static Map<String, String> trackerMap = null;
/** sorted map of name to announceURL=baseURL */
public Map<String, String> getTrackers() {
if (trackerMap != null) // only do this once, can't be updated while running
return trackerMap;
Map<String, String> rv = new TreeMap();
public Map<String, Tracker> getTrackerMap() {
return _trackerMap;
}
/**
* Unsorted, do not modify
*/
public Collection<Tracker> getTrackers() {
return _trackerMap.values();
}
/**
* Sorted copy
* @since 0.9.1
*/
public List<Tracker> getSortedTrackers() {
List<Tracker> rv = new ArrayList(_trackerMap.values());
Collections.sort(rv, new IgnoreCaseComparator());
return rv;
}
/** @since 0.9 */
private void initTrackerMap() {
String trackers = _config.getProperty(PROP_TRACKERS);
if ( (trackers == null) || (trackers.trim().length() <= 0) )
trackers = _context.getProperty(PROP_TRACKERS);
if ( (trackers == null) || (trackers.trim().length() <= 0) ) {
for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2)
rv.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]);
setDefaultTrackerMap(true);
} else {
StringTokenizer tok = new StringTokenizer(trackers, ",");
while (tok.hasMoreTokens()) {
String pair = tok.nextToken();
int split = pair.indexOf('=');
if (split <= 0)
continue;
String name = pair.substring(0, split).trim();
String url = pair.substring(split+1).trim();
if ( (name.length() > 0) && (url.length() > 0) )
rv.put(name, url);
String[] toks = trackers.split(",");
for (int i = 0; i < toks.length; i += 2) {
String name = toks[i].trim().replace("&#44;", ",");
String url = toks[i+1].trim().replace("&#44;", ",");
if ( (name.length() > 0) && (url.length() > 0) ) {
String urls[] = url.split("=", 2);
String url2 = urls.length > 1 ? urls[1] : "";
_trackerMap.put(name, new Tracker(name, urls[0], url2));
}
}
}
trackerMap = rv;
return trackerMap;
}
/** @since 0.9 */
public void setDefaultTrackerMap() {
setDefaultTrackerMap(true);
}
/** @since 0.9.1 */
private void setDefaultTrackerMap(boolean save) {
_trackerMap.clear();
for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2) {
String name = DEFAULT_TRACKERS[i];
String urls[] = DEFAULT_TRACKERS[i+1].split("=", 2);
String url2 = urls.length > 1 ? urls[1] : null;
_trackerMap.put(name, new Tracker(name, urls[0], url2));
}
if (save && _config.remove(PROP_TRACKERS) != null) {
saveConfig();
}
}
/** @since 0.9 */
public void saveTrackerMap() {
StringBuilder buf = new StringBuilder(2048);
boolean comma = false;
for (Map.Entry<String, Tracker> e : _trackerMap.entrySet()) {
if (comma)
buf.append(',');
else
comma = true;
Tracker t = e.getValue();
buf.append(e.getKey().replace(",", "&#44;")).append(',').append(t.announceURL.replace(",", "&#44;"));
if (t.baseURL != null)
buf.append('=').append(t.baseURL);
}
_config.setProperty(PROP_TRACKERS, buf.toString());
saveConfig();
}
private static class TorrentFilenameFilter implements FilenameFilter {
private static final TorrentFilenameFilter _filter = new TorrentFilenameFilter();
public static TorrentFilenameFilter instance() { return _filter; }
@@ -1415,15 +1714,147 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
public class SnarkManagerShutdown extends I2PAppThread {
@Override
/**
* If not connected, thread it, otherwise inline
* @since 0.9.1
*/
public void startTorrent(byte[] infoHash) {
for (Snark snark : _snarks.values()) {
if (DataHelper.eq(infoHash, snark.getInfoHash())) {
if (snark.isStarting() || !snark.isStopped()) {
addMessage("Torrent already started");
return;
}
boolean connected = _util.connected();
if ((!connected) && !_util.isConnecting())
addMessage(_("Opening the I2P tunnel"));
addMessage(_("Starting up torrent {0}", snark.getBaseName()));
if (connected) {
snark.startTorrent();
} else {
// mark it for the UI
snark.setStarting();
(new I2PAppThread(new ThreadedStarter(snark), "TorrentStarter", true)).start();
try { Thread.sleep(200); } catch (InterruptedException ie) {}
}
return;
}
}
addMessage("Torrent not found?");
}
/**
* If not connected, thread it, otherwise inline
* @since 0.9.1
*/
public void startAllTorrents() {
if (_util.connected()) {
startAll();
} else {
addMessage(_("Opening the I2P tunnel and starting all torrents."));
for (Snark snark : _snarks.values()) {
// mark it for the UI
snark.setStarting();
}
(new I2PAppThread(new ThreadedStarter(null), "TorrentStarterAll", true)).start();
try { Thread.sleep(200); } catch (InterruptedException ie) {}
}
}
/**
* Use null constructor param for all
* @since 0.9.1
*/
private class ThreadedStarter implements Runnable {
private final Snark snark;
public ThreadedStarter(Snark s) { snark = s; }
public void run() {
Set names = listTorrentFiles();
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
Snark snark = getTorrent((String)iter.next());
if ( (snark != null) && (!snark.isStopped()) )
snark.stopTorrent();
if (snark != null) {
if (snark.isStopped())
snark.startTorrent();
} else {
startAll();
}
}
}
/**
* Inline
* @since 0.9.1
*/
private void startAll() {
for (Snark snark : _snarks.values()) {
if (snark.isStopped())
snark.startTorrent();
}
}
/**
* Stop all running torrents, and close the tunnel after a delay
* to allow for announces.
* If called at router shutdown via Jetty shutdown hook -> webapp destroy() -> stop(),
* the tunnel won't actually be closed as the SimpleScheduler is already shutdown
* or will be soon, so we delay a few seconds inline.
* @param finalShutdown if true, sleep at the end if any torrents were running
* @since 0.9.1
*/
public void stopAllTorrents(boolean finalShutdown) {
_stopping = true;
if (finalShutdown && _log.shouldLog(Log.WARN))
_log.warn("SnarkManager final shutdown");
int count = 0;
for (Snark snark : _snarks.values()) {
if (!snark.isStopped()) {
if (count == 0)
addMessage(_("Stopping all torrents and closing the I2P tunnel."));
count++;
if (finalShutdown)
snark.stopTorrent(true);
else
stopTorrent(snark, false);
// Throttle since every unannounce is now threaded.
// How to do this without creating a ton of threads?
try { Thread.sleep(20); } catch (InterruptedException ie) {}
}
}
if (_util.connected()) {
if (count > 0) {
DHT dht = _util.getDHT();
if (dht != null)
dht.stop();
// Schedule this even for final shutdown, as there's a chance
// that it's just this webapp that is stopping.
_context.simpleScheduler().addEvent(new Disconnector(), 60*1000);
addMessage(_("Closing I2P tunnel after notifying trackers."));
if (finalShutdown) {
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
}
} else {
_util.disconnect();
_stopping = false;
addMessage(_("I2P tunnel closed."));
}
}
}
/** @since 0.9.1 */
private class Disconnector implements SimpleTimer.TimedEvent {
public void timeReached() {
if (_util.connected()) {
_util.disconnect();
_stopping = false;
addMessage(_("I2P tunnel closed."));
}
}
}
/**
* ignore case, current locale
* @since 0.9
*/
private static class IgnoreCaseComparator implements Comparator<Tracker> {
public int compare(Tracker l, Tracker r) {
return l.name.toLowerCase().compareTo(r.name.toLowerCase());
}
}
}

View File

@@ -26,6 +26,7 @@ import net.i2p.util.I2PAppThread;
/**
* Makes sure everything ends correctly when shutting down.
* @deprecated unused
*/
public class SnarkShutdown extends I2PAppThread
{
@@ -61,7 +62,7 @@ public class SnarkShutdown extends I2PAppThread
//Snark.debug("Halting TrackerClient...", Snark.INFO);
if (trackerclient != null)
trackerclient.halt();
trackerclient.halt(true);
//Snark.debug("Halting PeerCoordinator...", Snark.INFO);
if (coordinator != null)

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,16 +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;
@@ -50,9 +58,12 @@ public class Storage
private File[] RAFfile; // File to make it easier to reopen
/** priorities by file; default 0; may be null. @since 0.8.1 */
private int[] priorities;
/** is the file empty and sparse? */
private boolean[] isSparse;
private final StorageListener listener;
private final I2PSnarkUtil _util;
private final Log _log;
private /* FIXME final FIXME */ BitField bitfield; // BitField to represent the pieces
private int needed; // Number of pieces needed
@@ -62,6 +73,8 @@ 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;
@@ -73,20 +86,24 @@ public class Storage
private static final Map<String, String> _filterNameCache = new ConcurrentHashMap();
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;
@@ -94,17 +111,22 @@ 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, StorageListener listener)
public Storage(I2PSnarkUtil util, File baseFile, String announce,
boolean privateTorrent, StorageListener listener)
throws IOException
{
_util = util;
_log = util.getContext().logManager().getLog(Storage.class);
this.listener = listener;
// Create names, rafs and lengths arrays.
getFiles(baseFile);
@@ -120,6 +142,8 @@ 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 pcs = (int) ((total - 1)/pc_size) + 1;
@@ -155,9 +179,10 @@ 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);
lengthsList, piece_size, piece_hashes, total, privateTorrent);
}
@@ -190,6 +215,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);
@@ -201,7 +228,7 @@ public class Storage
RAFtime = new long[size];
RAFfile = new File[size];
priorities = new int[size];
isSparse = new boolean[size];
int i = 0;
Iterator it = files.iterator();
@@ -218,17 +245,21 @@ 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)
{
_util.debug("WARNING: Skipping '" + f
+ "' not a normal file.", Snark.WARNING);
if (_log.shouldLog(Log.WARN))
_log.warn("WARNING: Skipping '" + f
+ "' not a normal file.");
return;
}
for (int i = 0; i < files.length; i++)
@@ -268,6 +299,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
@@ -333,7 +381,8 @@ public class Storage
}
/**
* Must call setPiecePriorities() after calling this
* Must call Snark.updatePiecePriorities()
* (which calls getPiecePriorities()) after calling this.
* @param file canonical path (non-directory)
* @param pri default 0; <0 to disable
* @since 0.8.1
@@ -451,7 +500,8 @@ public class Storage
if (files == null)
{
// Create base as file.
_util.debug("Creating/Checking file: " + base, Snark.NOTICE);
if (_log.shouldLog(Log.INFO))
_log.info("Creating/Checking file: " + base);
if (!base.createNewFile() && !base.exists())
throw new IOException("Could not create file " + base);
@@ -461,6 +511,7 @@ public class Storage
RAFlock = new Object[1];
RAFtime = new long[1];
RAFfile = new File[1];
isSparse = new boolean[1];
lengths[0] = metainfo.getTotalLength();
RAFlock[0] = new Object();
RAFfile[0] = base;
@@ -474,7 +525,8 @@ public class Storage
else
{
// Create base as dir.
_util.debug("Creating/Checking directory: " + base, Snark.NOTICE);
if (_log.shouldLog(Log.INFO))
_log.info("Creating/Checking directory: " + base);
if (!base.mkdir() && !base.isDirectory())
throw new IOException("Could not create directory " + base);
@@ -487,6 +539,7 @@ public class Storage
RAFlock = new Object[size];
RAFtime = new long[size];
RAFfile = new File[size];
isSparse = new boolean[size];
for (int i = 0; i < size; i++)
{
List<String> path = files.get(i);
@@ -532,19 +585,22 @@ public class Storage
bitfield = savedBitField;
needed = metainfo.getPieces() - bitfield.count();
_probablyComplete = complete();
_util.debug("Found saved state and files unchanged, skipping check", Snark.NOTICE);
if (_log.shouldLog(Log.INFO))
_log.info("Found saved state and files unchanged, skipping check");
} else {
// the following sets the needed variable
changed = true;
checkCreateFiles(false);
}
if (complete()) {
_util.debug("Torrent is complete", Snark.NOTICE);
if (_log.shouldLog(Log.INFO))
_log.info("Torrent is complete");
} else {
// fixme saved priorities
if (files != null)
priorities = new int[files.size()];
_util.debug("Still need " + needed + " out of " + metainfo.getPieces() + " pieces", Snark.NOTICE);
if (_log.shouldLog(Log.INFO))
_log.info("Still need " + needed + " out of " + metainfo.getPieces() + " pieces");
}
}
@@ -679,11 +735,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.
@@ -700,6 +770,7 @@ public class Storage
}
// Make sure all files are available and of correct length
// The files should all exist as they have been created with zero length by createFilesFromNames()
for (int i = 0; i < rafs.length; i++)
{
long length = RAFfile[i].length();
@@ -721,9 +792,11 @@ public class Storage
} else {
String msg = "File '" + names[i] + "' exists, but has wrong length (expected " +
lengths[i] + " but found " + length + ") - repairing corruption";
SnarkManager.instance().addMessage(msg);
_util.debug(msg, Snark.ERROR);
if (listener != null)
listener.addMessage(msg);
_log.error(msg);
changed = true;
resume = true;
_probablyComplete = false; // to force RW
synchronized(RAFlock[i]) {
checkRAF(i);
@@ -797,28 +870,66 @@ public class Storage
}
}
/** this calls openRAF(); caller must synnchronize and call closeRAF() */
/**
* This creates a (presumably) sparse file so that reads won't fail with IOE.
* Sets isSparse[nr] = true. balloonFile(nr) should be called later to
* defrag the file.
*
* This calls openRAF(); caller must synchronize and call closeRAF().
*/
private void allocateFile(int nr) throws IOException
{
// caller synchronized
openRAF(nr, false); // RW
// XXX - Is this the best way to make sure we have enough space for
// the whole file?
long remaining = lengths[nr];
if (listener != null)
listener.storageCreateFile(this, names[nr], remaining);
final int ZEROBLOCKSIZE = (int) Math.min(remaining, 32*1024);
byte[] zeros = new byte[ZEROBLOCKSIZE];
while (remaining > 0) {
int size = (int) Math.min(remaining, ZEROBLOCKSIZE);
rafs[nr].write(zeros, 0, size);
remaining -= size;
}
rafs[nr].setLength(remaining);
// don't bother ballooning later on Windows since there is no sparse file support
// until JDK7 using the JSR-203 interface.
// RAF seeks/writes do not create sparse files.
// Windows will zero-fill up to the point of the write, which
// will make the file fairly unfragmented, on average, at least until
// near the end where it will get exponentially more fragmented.
if (!_isWindows)
isSparse[nr] = true;
// caller will close rafs[nr]
if (listener != null)
listener.storageAllocated(this, lengths[nr]);
}
/**
* This "balloons" the file with zeros to eliminate disk fragmentation.,
* Overwrites the entire file with zeros. Sets isSparse[nr] = false.
*
* Caller must synchronize and call checkRAF() or openRAF().
* @since 0.9.1
*/
private void balloonFile(int nr) throws IOException
{
if (_log.shouldLog(Log.INFO))
_log.info("Ballooning " + nr + ": " + RAFfile[nr]);
long remaining = lengths[nr];
final int ZEROBLOCKSIZE = (int) Math.min(remaining, 32*1024);
byte[] zeros = new byte[ZEROBLOCKSIZE];
rafs[nr].seek(0);
// 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;
}
/**
* Closes the Storage and makes sure that all RandomAccessFiles are
@@ -837,7 +948,7 @@ public class Storage
closeRAF(i);
}
} catch (IOException ioe) {
_util.debug("Error closing " + RAFfile[i], Snark.ERROR, ioe);
_log.error("Error closing " + RAFfile[i], ioe);
// gobble gobble
}
}
@@ -848,78 +959,99 @@ 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) {
_util.debug("Out of memory, can't honor request for piece " + piece, Snark.WARNING, 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.
* @exception IOException when some storage related error occurs.
*/
public boolean putPiece(int piece, byte[] ba) throws IOException
public boolean putPiece(PartialPiece pp) throws IOException
{
// First check if the piece is correct.
// Copy the array first to be paranoid.
byte[] bs = (byte[]) ba.clone();
int length = bs.length;
boolean correctHash = metainfo.checkPiece(piece, bs, 0, length);
if (listener != null)
listener.storageChecked(this, piece, correctHash);
if (!correctHash)
return false;
int piece = pp.getPiece();
try {
synchronized(bitfield) {
if (bitfield.get(piece))
return true; // No need to store twice.
}
synchronized(bitfield)
{
if (bitfield.get(piece))
return true; // No need to store twice.
}
// 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 (!correctHash) {
if (listener != null)
listener.storageChecked(this, piece, false);
return false;
}
// Early typecast, avoid possibly overflowing a temp integer
long start = (long) piece * (long) piece_size;
int i = 0;
long raflen = lengths[i];
while (start > raflen)
{
i++;
start -= raflen;
raflen = lengths[i];
}
// Early typecast, avoid possibly overflowing a temp integer
long start = (long) piece * (long) piece_size;
int i = 0;
long raflen = lengths[i];
while (start > raflen) {
i++;
start -= raflen;
raflen = lengths[i];
}
int written = 0;
int off = 0;
while (written < length)
{
int need = length - written;
int len = (start + need < raflen) ? need : (int)(raflen - start);
synchronized(RAFlock[i])
{
checkRAF(i);
rafs[i].seek(start);
rafs[i].write(bs, off + written, len);
}
written += len;
if (need - len > 0)
{
i++;
raflen = lengths[i];
start = 0;
int written = 0;
int off = 0;
int length = metainfo.getPieceLength(piece);
while (written < length) {
int need = length - written;
int len = (start + need < raflen) ? need : (int)(raflen - start);
synchronized(RAFlock[i]) {
checkRAF(i);
if (isSparse[i]) {
// If the file is a newly created sparse file,
// AND we aren't skipping it, balloon it with all
// zeros to un-sparse it by allocating the space.
// Obviously this could take a while.
// Once we have written to it, it isn't empty/sparse any more.
if (priorities == null || priorities[i] >= 0)
balloonFile(i);
else
isSparse[i] = false;
}
rafs[i].seek(start);
//rafs[i].write(bs, off + written, len);
pp.write(rafs[i], off + written, len);
}
written += len;
if (need - len > 0) {
i++;
raflen = lengths[i];
start = 0;
}
}
} finally {
pp.release();
}
changed = true;
@@ -936,6 +1068,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
@@ -950,13 +1085,14 @@ public class Storage
if (needed > 0) {
if (listener != null)
listener.setWantedPieces(this);
_util.debug("WARNING: Not really done, missing " + needed
+ " pieces", Snark.WARNING);
if (_log.shouldLog(Log.WARN))
_log.warn("WARNING: Not really done, missing " + needed
+ " pieces");
}
}
return true;
}
}
/**
* This is a dup of MetaInfo.getPieceLength() but we need it
@@ -1021,7 +1157,7 @@ public class Storage
/**
* Close unused RAFs - call periodically
*/
private static final long RAFCloseDelay = 7*60*1000;
private static final long RAFCloseDelay = 4*60*1000;
public void cleanRAFs() {
long cutoff = System.currentTimeMillis() - RAFCloseDelay;
for (int i = 0; i < RAFlock.length; i++) {
@@ -1072,4 +1208,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, 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

@@ -23,7 +23,7 @@ package org.klomp.snark;
/**
* Callback used when Storage changes.
*/
public interface StorageListener
interface StorageListener
{
/**
* Called when the storage creates a new file of a given length.
@@ -61,4 +61,6 @@ public interface StorageListener
*
*/
void setWantedPieces(Storage storage);
void addMessage(String message);
}

View File

@@ -0,0 +1,28 @@
/*
* Released into the public domain
* with no warranty of any kind, either expressed or implied.
*/
package org.klomp.snark;
/**
* A structure for known trackers
*
* @since 0.9.1
*/
public class Tracker {
public final String name;
public final String announceURL;
public final String baseURL;
public final boolean supportsDetails;
/**
* @param baseURL The web site, may be null
*/
public Tracker(String name, String announceURL, String baseURL) {
this.name = name;
this.announceURL = announceURL;
this.baseURL = baseURL;
this.supportsDetails = name.contains("tracker2.postman.i2p");
}
}

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;
@@ -27,7 +28,9 @@ import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
@@ -35,48 +38,83 @@ import java.util.Random;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
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;
/**
* Informs metainfo tracker of events and gets new peers for peer
* coordinator.
*
* start() creates a thread and starts it.
* At the end of each run, a TimedEvent is queued on the SimpleTimer2 queue.
* The TimedEvent creates a new thread and starts it, so it does not
* clog SimpleTimer2.
*
* The thread runs one pass through the trackers, the PEX, and the DHT,
* then queues a new TimedEvent and exits.
*
* Thus there are only threads that are actively announcing, not one thread per torrent forever.
*
* start() may be called again after halt().
*
* @author Mark Wielaard (mark@klomp.org)
*/
public class TrackerClient extends I2PAppThread
{
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(TrackerClient.class);
public class TrackerClient implements Runnable {
private final Log _log;
private static final String NO_EVENT = "";
private static final String STARTED_EVENT = "started";
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.
private final static int DELAY_MUL = 1500; // 1.5 secs.
private final static int DELAY_RAND = 6*1000;
private final static int MAX_REGISTER_FAILS = 10; // * INITIAL_SLEEP = 15m to register
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 = 15*60*1000;
private final static long MIN_DHT_ANNOUNCE_INTERVAL = 10*60*1000;
private I2PSnarkUtil _util;
private final I2PSnarkUtil _util;
private final MetaInfo meta;
private final String infoHash;
private final String peerID;
private final String additionalTrackerURL;
private final PeerCoordinator coordinator;
private final Snark snark;
private final int port;
private final String _threadName;
private boolean stop;
private boolean started;
private List trackers;
private volatile boolean stop = true;
private volatile boolean started;
private volatile boolean _initialized;
private volatile int _runCount;
// running thread so it can be interrupted
private volatile Thread _thread;
// queued event so it can be cancelled
private volatile SimpleTimer2.TimedEvent _event;
// these 2 used in loop()
private volatile boolean runStarted;
private volatile int consecutiveFails;
private boolean completed;
private volatile boolean _fastUnannounce;
private long lastDHTAnnounce;
private final List<Tracker> trackers;
private final List<Tracker> backupTrackers;
/**
* Call start() to start it.
*
* @param meta null if in magnet mode
* @param additionalTrackerURL may be null, from the ?tr= param in magnet mode, otherwise ignored
*/
@@ -86,20 +124,33 @@ public class TrackerClient extends I2PAppThread
super();
// Set unique name.
String id = urlencode(snark.getID());
setName("TrackerClient " + id.substring(id.length() - 12));
_threadName = "TrackerClient " + id.substring(id.length() - 12);
_util = util;
_log = util.getContext().logManager().getLog(TrackerClient.class);
this.meta = meta;
this.additionalTrackerURL = additionalTrackerURL;
this.coordinator = coordinator;
this.snark = snark;
this.port = 6881; //(port == -1) ? 9 : port;
this.infoHash = urlencode(snark.getInfoHash());
this.peerID = urlencode(snark.getID());
this.trackers = new ArrayList(2);
this.backupTrackers = new ArrayList(2);
}
@Override
public void start() {
if (stop) throw new RuntimeException("Dont rerun me, create a copy");
super.start();
public synchronized void start() {
if (!stop) {
if (_log.shouldLog(Log.WARN))
_log.warn("Already started: " + _threadName);
return;
}
stop = false;
consecutiveFails = 0;
runStarted = false;
_fastUnannounce = false;
_thread = new I2PAppThread(this, _threadName + " #" + (++_runCount), true);
_thread.start();
started = true;
}
@@ -108,11 +159,50 @@ public class TrackerClient extends I2PAppThread
/**
* Interrupts this Thread to stop it.
* @param fast if true, limit the life of the unannounce threads
*/
public void halt()
{
stop = true;
this.interrupt();
public synchronized void halt(boolean fast) {
boolean wasStopped = stop;
if (wasStopped) {
if (_log.shouldLog(Log.WARN))
_log.warn("Already stopped: " + _threadName);
} else {
if (_log.shouldLog(Log.WARN))
_log.warn("Stopping: " + _threadName);
stop = true;
}
SimpleTimer2.TimedEvent e = _event;
if (e != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Cancelling next announce " + _threadName);
e.cancel();
_event = null;
}
Thread t = _thread;
if (t != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Interrupting " + t.getName());
t.interrupt();
}
_fastUnannounce = true;
if (!wasStopped)
unannounce();
}
private void queueLoop(long delay) {
_event = new Runner(delay);
}
private class Runner extends SimpleTimer2.TimedEvent {
public Runner(long delay) {
super(_util.getContext().simpleTimer2(), delay);
}
public void timeReached() {
_event = null;
_thread = new I2PAppThread(TrackerClient.this, _threadName + " #" + (++_runCount), true);
_thread.start();
}
}
private boolean verifyConnected() {
@@ -125,20 +215,56 @@ public class TrackerClient extends I2PAppThread
return !stop && _util.connected();
}
@Override
public void run()
{
String infoHash = urlencode(snark.getInfoHash());
String peerID = urlencode(snark.getID());
/**
* Setup the first time only,
* then one pass (usually) through the trackers, PEX, and DHT.
* This will take several seconds to several minutes.
*/
public void run() {
long begin = _util.getContext().clock().now();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Start " + Thread.currentThread().getName());
try {
if (!_initialized) {
setup();
}
if (trackers.isEmpty() && _util.getDHT() == null) {
stop = true;
this.snark.addMessage(_util.getString("No valid trackers for {0} - enable opentrackers or DHT?",
this.snark.getBaseName()));
_log.error("No valid trackers for " + this.snark.getBaseName());
this.snark.stopTorrent();
return;
}
if (!_initialized) {
_initialized = true;
// FIXME only when starting everybody at once, not for a single torrent
long delay = _util.getContext().random().nextInt(30*1000);
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {}
}
loop();
} finally {
// don't hold ref
_thread = null;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Finish " + Thread.currentThread().getName() +
" after " + DataHelper.formatDuration(_util.getContext().clock().now() - begin));
}
}
/**
* Do this one time only (not every time it is started).
* @since 0.9.1
*/
private void setup() {
// Construct the list of trackers for this torrent,
// starting with the primary one listed in the metainfo,
// followed by the secondary open trackers
// It's painful, but try to make sure if an open tracker is also
// the primary tracker, that we don't add it twice.
// todo: check for b32 matches as well
trackers = new ArrayList(2);
String primary = null;
if (meta != null)
primary = meta.getAnnounce();
@@ -147,18 +273,20 @@ public class TrackerClient extends I2PAppThread
if (primary != null) {
if (isValidAnnounce(primary)) {
trackers.add(new Tracker(primary, true));
_log.debug("Announce: [" + primary + "] infoHash: " + infoHash);
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) {
if (meta == null || !meta.isPrivate()) {
List<String> tlist = _util.getOpenTrackers();
for (int i = 0; i < tlist.size(); i++) {
String url = (String)tlist.get(i);
String url = tlist.get(i);
if (!isValidAnnounce(url)) {
_log.error("Bad announce URL: [" + url + "]");
continue;
@@ -181,73 +309,126 @@ public class TrackerClient extends I2PAppThread
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);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Additional announce: [" + url + "] for infoHash: " + infoHash);
}
}
if (trackers.isEmpty()) {
stop = true;
// FIXME translate
SnarkManager.instance().addMessage("No valid trackers for " + this.snark.getBaseName() + " - enable opentrackers?");
_log.error("No valid trackers for " + this.snark.getBaseName());
// FIXME keep going if DHT enabled
this.snark.stopTorrent();
return;
// 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 (!isValidAnnounce(url)) {
_log.error("Bad announce URL: [" + url + "]");
continue;
}
int slash = url.indexOf('/', 7);
if (slash <= 7) {
_log.error("Bad announce URL: [" + url + "]");
continue;
}
String dest = _util.lookup(url.substring(7, slash));
if (dest == null) {
_log.error("Announce host unknown: [" + url.substring(7, slash) + "]");
continue;
}
backupTrackers.add(new Tracker(url, false));
if (_log.shouldLog(Log.DEBUG))
_log.debug("Backup announce: [" + url + "] for infoHash: " + infoHash);
}
if (backupTrackers.isEmpty())
backupTrackers.add(new Tracker(DEFAULT_BACKUP_TRACKER, false));
}
this.completed = coordinator.getLeft() == 0;
}
long uploaded = coordinator.getUploaded();
long downloaded = coordinator.getDownloaded();
long left = coordinator.getLeft();
boolean completed = (left == 0);
int sleptTime = 0;
/**
* 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.
* @since 0.9.1
*/
private void loop() {
try
{
if (!verifyConnected()) return;
boolean runStarted = false;
boolean firstTime = true;
int consecutiveFails = 0;
Random r = I2PAppContext.getGlobalContext().random();
// normally this will only go once, then call queueLoop() and return
while(!stop)
{
if (!verifyConnected()) {
stop = true;
return;
}
// Local DHT tracker announce
if (_util.getDHT() != null)
_util.getDHT().announce(snark.getInfoHash());
try
{
DHT dht = _util.getDHT();
if (dht != null && (meta == null || !meta.isPrivate()))
dht.announce(snark.getInfoHash());
int maxSeenPeers = 0;
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;
}
// we could try and total the unique peers but that's too hard for now
snark.setTrackerSeenPeers(maxSeenPeers);
if (stop)
return;
try {
// Sleep some minutes...
// Sleep the minimum interval for all the trackers, but 60s minimum
// except for the first time...
int delay;
Random r = _util.getContext().random();
int random = r.nextInt(120*1000);
if (firstTime) {
delay = r.nextInt(30*1000);
firstTime = false;
} else if (completed && runStarted)
if (completed && runStarted)
delay = 3*SLEEP*60*1000 + random;
else if (snark.getTrackerProblems() != null && ++consecutiveFails < MAX_CONSEC_FAILS)
delay = INITIAL_SLEEP;
else if ((!runStarted) && _runCount < MAX_CONSEC_FAILS)
delay = INITIAL_SLEEP;
else
// sleep a while, when we wake up we will contact only the trackers whose intervals have passed
delay = SLEEP*60*1000 + random;
if (delay > 0)
if (delay > 20*1000) {
// put ourselves on SimpleTimer2
if (_log.shouldLog(Log.DEBUG))
_log.debug("Requeueing in " + DataHelper.formatDuration(delay) + ": " + Thread.currentThread().getName());
queueLoop(delay);
return;
} else if (delay > 0) {
Thread.sleep(delay);
}
catch(InterruptedException interrupt)
{
// ignore
}
}
} catch(InterruptedException interrupt) {}
} // *** end of while loop
} // try
catch (Throwable t)
{
_log.error("TrackerClient: " + t, t);
if (t instanceof OutOfMemoryError)
throw (OutOfMemoryError)t;
}
}
if (stop)
break;
if (!verifyConnected()) return;
uploaded = coordinator.getUploaded();
downloaded = coordinator.getDownloaded();
left = coordinator.getLeft(); // -1 in magnet mode
/**
* @return max peers seen
*/
private int getPeersFromTrackers(List<Tracker> trckrs) {
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;
@@ -258,15 +439,12 @@ public class TrackerClient extends I2PAppThread
}
else
event = NO_EVENT;
// *** loop once for each tracker
// Only do a request when necessary.
sleptTime = 0;
int maxSeenPeers = 0;
for (Iterator iter = trackers.iterator(); iter.hasNext(); ) {
Tracker tr = (Tracker)iter.next();
for (Tracker tr : trckrs) {
if ((!stop) && (!tr.stop) &&
(completed || coordinator.needPeers()) &&
(completed || coordinator.needOutboundPeers() || !tr.started) &&
(event.equals(COMPLETED_EVENT) || System.currentTimeMillis() > tr.lastRequestTime + tr.interval))
{
try
@@ -292,25 +470,26 @@ public class TrackerClient extends I2PAppThread
snark.setTrackerSeenPeers(tr.seenPeers);
// pass everybody over to our tracker
if (_util.getDHT() != null) {
DHT dht = _util.getDHT();
if (dht != null) {
for (Peer peer : peers) {
_util.getDHT().announce(snark.getInfoHash(), peer.getPeerID().getDestHash());
dht.announce(snark.getInfoHash(), peer.getPeerID().getDestHash());
}
}
if ( (left != 0) && (!completed) ) {
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()) {
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 = (DELAY_MUL * r.nextInt(10)) + DELAY_MIN;
sleptTime += delay;
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
@@ -319,22 +498,23 @@ public class TrackerClient extends I2PAppThread
catch (IOException ioe)
{
// Probably not fatal (if it doesn't last to long...)
_util.debug
if (_log.shouldLog(Log.WARN))
_log.warn
("WARNING: Could not contact tracker at '"
+ tr.announce + "': " + ioe, Snark.WARNING);
+ 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 (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;
@@ -342,101 +522,167 @@ public class TrackerClient extends I2PAppThread
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
if (left > 0 && coordinator.needPeers() && !stop) {
int rv = 0;
if (coordinator.needOutboundPeers() && (meta == null || !meta.isPrivate()) && !stop) {
Set<PeerID> pids = coordinator.getPEXPeers();
if (!pids.isEmpty()) {
_util.debug("Got " + pids.size() + " from PEX", Snark.INFO);
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()) {
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
Peer cur = it.next();
if (coordinator.addPeer(cur) && it.hasNext()) {
int delay = (DELAY_MUL * r.nextInt(10)) + DELAY_MIN;
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
if (_util.getDHT() != null && !stop) {
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 (left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers())
if (!coordinator.needOutboundPeers())
numwant = 1;
else
numwant = _util.getMaxConnections();
List<Hash> hashes = _util.getDHT().getPeers(snark.getInfoHash(), numwant, 2*60*1000);
_util.debug("Got " + hashes + " from DHT", Snark.INFO);
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) {
int good = _util.getDHT().announce(snark.getInfoHash(), 8, 5*60*1000);
_util.debug("Sent " + good + " good announces to DHT", Snark.INFO);
// 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());
peers.add(new Peer(pID, snark.getID(), snark.getInfoHash(), snark.getMetaInfo()));
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()) {
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
Peer cur = it.next();
if (coordinator.addPeer(cur) && it.hasNext()) {
int delay = (DELAY_MUL * r.nextInt(10)) + DELAY_MIN;
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;
}
// we could try and total the unique peers but that's too hard for now
snark.setTrackerSeenPeers(maxSeenPeers);
if (!runStarted)
_util.debug(" Retrying in one minute...", Snark.DEBUG);
} // *** end of while loop
} // try
catch (Throwable t)
{
_util.debug("TrackerClient: " + t, Snark.ERROR, t);
if (t instanceof OutOfMemoryError)
throw (OutOfMemoryError)t;
/**
* Creates a thread for each tracker in parallel if tunnel is still open
* @since 0.9.1
*/
private void unannounce() {
// Local DHT tracker unannounce
DHT dht = _util.getDHT();
if (dht != null)
dht.unannounce(snark.getInfoHash());
int i = 0;
for (Tracker tr : trackers) {
if (_util.connected() &&
tr.started && (!tr.stop) && tr.trackerProblems == null) {
try {
(new I2PAppThread(new Unannouncer(tr), _threadName + " U" + (++i), true)).start();
} catch (OutOfMemoryError oom) {
// probably ran out of threads, ignore
tr.reset();
}
} else {
tr.reset();
}
}
finally
{
// Local DHT tracker unannounce
if (_util.getDHT() != null)
_util.getDHT().unannounce(snark.getInfoHash());
}
/**
* Send "stopped" to a single tracker
* @since 0.9.1
*/
private class Unannouncer implements Runnable {
private final Tracker tr;
public Unannouncer(Tracker tr) {
this.tr = tr;
}
public void run() {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Running unannounce " + _threadName + " to " + tr.announce);
long uploaded = coordinator.getUploaded();
long downloaded = coordinator.getDownloaded();
long left = coordinator.getLeft();
try
{
// try to contact everybody we can
// Don't try to restart I2CP connection just to say goodbye
for (Iterator iter = trackers.iterator(); iter.hasNext(); ) {
if (!_util.connected()) return;
Tracker tr = (Tracker)iter.next();
if (tr.started && (!tr.stop) && tr.trackerProblems == null)
doRequest(tr, infoHash, peerID, uploaded,
if (_util.connected()) {
if (tr.started && (!tr.stop) && tr.trackerProblems == null)
doRequest(tr, infoHash, peerID, uploaded,
downloaded, left, STOPPED_EVENT);
}
}
}
catch(IOException ioe) { /* ignored */ }
}
tr.reset();
}
}
private TrackerInfo doRequest(Tracker tr, String infoHash,
@@ -444,48 +690,58 @@ public class TrackerClient extends I2PAppThread
long downloaded, long left, String event)
throws IOException
{
// What do we send for left in magnet mode? Can we omit it?
long tleft = left >= 0 ? left : 1;
String s = tr.announce
+ "?info_hash=" + infoHash
+ "&peer_id=" + peerID
+ "&port=" + port
+ "&ip=" + _util.getOurIPString() + ".i2p"
+ "&uploaded=" + uploaded
+ "&downloaded=" + downloaded
+ "&left=" + tleft
+ "&compact=1" // NOTE: opentracker will return 400 for &compact alone
+ ((! event.equals(NO_EVENT)) ? ("&event=" + event) : "");
if (left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers())
s += "&numwant=0";
StringBuilder buf = new StringBuilder(512);
buf.append(tr.announce);
if (tr.announce.contains("?"))
buf.append('&');
else
s += "&numwant=" + _util.getMaxConnections();
_util.debug("Sending TrackerClient request: " + s, Snark.INFO);
buf.append('?');
buf.append("info_hash=").append(infoHash)
.append("&peer_id=").append(peerID)
.append("&port=").append(port)
.append("&ip=" ).append(_util.getOurIPString()).append(".i2p")
.append("&uploaded=").append(uploaded)
.append("&downloaded=").append(downloaded)
.append("&left=");
// What do we send for left in magnet mode? Can we omit it?
if (left >= 0)
buf.append(left);
else
buf.append('1');
buf.append("&compact=1"); // NOTE: opentracker will return 400 for &compact alone
if (! event.equals(NO_EVENT))
buf.append("&event=").append(event);
buf.append("&numwant=");
boolean small = left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needOutboundPeers();
if (small)
buf.append('0');
else
buf.append(_util.getMaxConnections());
String s = buf.toString();
if (_log.shouldLog(Log.INFO))
_log.info("Sending TrackerClient request: " + s);
tr.lastRequestTime = System.currentTimeMillis();
File fetched = _util.get(s);
// Don't wait for a response to stopped when shutting down
boolean fast = _fastUnannounce && event.equals(STOPPED_EVENT);
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.debug("TrackerClient response: " + info, Snark.INFO);
snark.getInfoHash(), snark.getMetaInfo(), _util);
if (_log.shouldLog(Log.INFO))
_log.info("TrackerClient response: " + info);
String failure = info.getFailureReason();
if (failure != null)
throw new IOException(failure);
tr.interval = info.getInterval() * 1000;
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();
}
}
/**
@@ -522,7 +778,7 @@ public class TrackerClient extends I2PAppThread
* @return true for i2p hosts only
* @since 0.7.12
*/
static boolean isValidAnnounce(String ann) {
public static boolean isValidAnnounce(String ann) {
URL url;
try {
url = new URL(ann);
@@ -552,6 +808,13 @@ public class TrackerClient extends I2PAppThread
announce = a;
isPrimary = p;
interval = INITIAL_SLEEP;
}
/**
* Call before restarting
* @since 0.9.1
*/
public void reset() {
lastRequestTime = 0;
trackerProblems = null;
stop = false;

View File

@@ -38,7 +38,7 @@ import org.klomp.snark.bencode.InvalidBEncodingException;
* Compact format 1 - a list of hashes - early format for testing
* Compact format 2 - One big string of concatenated hashes - official format
*/
public class TrackerInfo
class TrackerInfo
{
private final String failure_reason;
private final int interval;
@@ -47,19 +47,19 @@ public class TrackerInfo
private int incomplete;
/** @param metainfo may be null */
public TrackerInfo(InputStream in, byte[] my_id, byte[] infohash, MetaInfo metainfo)
public TrackerInfo(InputStream in, byte[] my_id, byte[] infohash, MetaInfo metainfo, I2PSnarkUtil util)
throws IOException
{
this(new BDecoder(in), my_id, infohash, metainfo);
this(new BDecoder(in), my_id, infohash, metainfo, util);
}
private TrackerInfo(BDecoder be, byte[] my_id, byte[] infohash, MetaInfo metainfo)
private TrackerInfo(BDecoder be, byte[] my_id, byte[] infohash, MetaInfo metainfo, I2PSnarkUtil util)
throws IOException
{
this(be.bdecodeMap().getMap(), my_id, infohash, metainfo);
this(be.bdecodeMap().getMap(), my_id, infohash, metainfo, util);
}
private TrackerInfo(Map m, byte[] my_id, byte[] infohash, MetaInfo metainfo)
private TrackerInfo(Map m, byte[] my_id, byte[] infohash, MetaInfo metainfo, I2PSnarkUtil util)
throws IOException
{
BEValue reason = (BEValue)m.get("failure reason");
@@ -85,10 +85,10 @@ public class TrackerInfo
Set<Peer> p;
try {
// One big string (the official compact format)
p = getPeers(bePeers.getBytes(), my_id, infohash, metainfo);
p = getPeers(bePeers.getBytes(), my_id, infohash, metainfo, util);
} catch (InvalidBEncodingException ibe) {
// List of Dictionaries or List of Strings
p = getPeers(bePeers.getList(), my_id, infohash, metainfo);
p = getPeers(bePeers.getList(), my_id, infohash, metainfo, util);
}
peers = p;
}
@@ -124,7 +124,7 @@ public class TrackerInfo
******/
/** List of Dictionaries or List of Strings */
private static Set<Peer> getPeers(List<BEValue> l, byte[] my_id, byte[] infohash, MetaInfo metainfo)
private static Set<Peer> getPeers(List<BEValue> l, byte[] my_id, byte[] infohash, MetaInfo metainfo, I2PSnarkUtil util)
throws IOException
{
Set<Peer> peers = new HashSet(l.size());
@@ -138,7 +138,7 @@ public class TrackerInfo
try {
// Case 2 - compact - A list of 32-byte binary strings (hashes)
// This was just for testing and is not the official format
peerID = new PeerID(bev.getBytes());
peerID = new PeerID(bev.getBytes(), util);
} catch (InvalidBEncodingException ibe2) {
// don't let one bad entry spoil the whole list
//Snark.debug("Discarding peer from list: " + ibe, Snark.ERROR);
@@ -157,7 +157,7 @@ public class TrackerInfo
* One big string of concatenated 32-byte hashes
* @since 0.8.1
*/
private static Set<Peer> getPeers(byte[] l, byte[] my_id, byte[] infohash, MetaInfo metainfo)
private static Set<Peer> getPeers(byte[] l, byte[] my_id, byte[] infohash, MetaInfo metainfo, I2PSnarkUtil util)
throws IOException
{
int count = l.length / HASH_LENGTH;
@@ -168,7 +168,7 @@ public class TrackerInfo
byte[] hash = new byte[HASH_LENGTH];
System.arraycopy(l, i * HASH_LENGTH, hash, 0, HASH_LENGTH);
try {
peerID = new PeerID(hash);
peerID = new PeerID(hash, util);
} catch (InvalidBEncodingException ibe) {
// won't happen
continue;
@@ -195,6 +195,7 @@ public class TrackerInfo
return failure_reason;
}
/** in seconds */
public int getInterval()
{
return interval;

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

@@ -4,7 +4,7 @@ package org.klomp.snark.dht;
* GPLv2
*/
import java.util.List;
import java.util.Collection;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
@@ -12,15 +12,21 @@ import net.i2p.data.Hash;
/**
* Stub for KRPC
* @since 0.8.4
*/
public interface DHT {
/**
* @return The UDP port that should be included in a PORT message.
* @return The UDP query port
*/
public int getPort();
/**
* @return The UDP response port
*/
public int getRPort();
/**
* Ping. We don't have a NID yet so the node is presumed
* to be absent from our DHT.
@@ -37,9 +43,9 @@ public interface DHT {
* @param ih the Info Hash (torrent)
* @param max maximum number of peers to return
* @param maxWait the maximum time to wait (ms) must be > 0
* @return list or empty list (never null)
* @return possibly empty (never null)
*/
public List<Hash> getPeers(byte[] ih, int max, long maxWait);
public Collection<Hash> getPeers(byte[] ih, int max, long maxWait);
/**
* Announce to ourselves.
@@ -79,4 +85,19 @@ public interface DHT {
* @return the number of successful announces, not counting ourselves.
*/
public int announce(byte[] ih, int max, long maxWait);
/**
* Stop everything.
*/
public void stop();
/**
* Known nodes, not estimated total network size.
*/
public int size();
/**
* Debug info, HTML formatted
*/
public String renderStatusHTML();
}

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