Compare commits

..

391 Commits

Author SHA1 Message Date
zzz
fd606064d9 0.9.22 2015-09-12 13:55:30 +00:00
zzz
9d05424202 Router: Reduce rekey probability from 10% to 5% 2015-09-11 13:24:10 +00:00
kytv
157d494dee bump build to -8-rc 2015-09-11 00:54:45 +00:00
kytv
fa792a9d5e GeoIP db updates from 2015-09-02. 2015-09-11 00:54:03 +00:00
kytv
ab134261f0 Translation updates from Transifex 2015-09-11 00:53:13 +00:00
dg2-new
de2431e9ee Fix auto-start of new .torrents in the Snark folder 2015-09-07 18:18:16 +00:00
kytv
c4cbd7d5c4 (hopefully temporarily) disable netdb.rows.io as it's been down for nearly a month. 2015-09-06 08:01:28 +00:00
zzz
e978bb81a0 checked in correct file 2015-09-05 14:02:21 +00:00
zzz
2c6edf401f add extra to bumpBuild output after change 2015-09-04 21:15:48 +00:00
zzz
fe69d3b8f7 UPnP: Fix "content not allowed in trailing section" (tickets #481, #1653)
patch from 'kay" in #1653, dev agreement received
2015-09-04 21:05:38 +00:00
kytv
61edd01e3d Switch URL/certificate for backup's reseed server 2015-09-04 18:44:05 +00:00
zzz
483d7c43ee Router: Change thread name so it truncates better (ticket #1648) 2015-09-01 11:56:58 +00:00
zzz
7c703953be Data: Cache P256 and Ed255i9 key certificates
- Enable P256 caching
 - Create cached Ed25519 cert and enable
 - Fix cached P256 hashcode
2015-08-31 13:25:58 +00:00
zzz
f577a94012 i2psnark: Change default sig type to Ed25519 2015-08-31 13:19:29 +00:00
zzz
b10b8581cc Router:
- Change default RI sig type to Ed25519, with a 10% chance od
     rekeying from DSA at each restart
   - Don't initialize KeyManager before selecting sig type
   - Don't log KeyManager error when changing sig type
2015-08-29 14:20:13 +00:00
zzz
601376561b add Closeable/Flushable interfaces 2015-08-27 14:36:19 +00:00
zzz
5a11a28a35 i2psnark:
- Return partial piece to coordinator after reject
   - Fix tracking of downloaded portion of piece after reject
   - Send reject on receipt of bad request
   - Mark piece unrequested after receiving bad data, so it
     will be requested again, but not from the same peer
   - Fix NPE in Request constructor on error
   - Fix stuck before completion due to reject handling (ticket #1633)
2015-08-24 17:30:32 +00:00
kytv
fde0ae8349 sync debian/changelog with packaged version 2015-08-02 15:06:50 +00:00
kytv
b5944045fb sync apparmor rules with the 0.9.21 package 2015-08-02 15:04:08 +00:00
zzz
ecd0231cd0 Fix console SSL excluded ciphers (thx lazyg)
Fix typo in local address in I2PSSLSocketFactory
Another findbugs char encoding fix
Add keystore password option to SU3File command line
2015-08-02 12:58:00 +00:00
zzz
44b35f328b 0.9.21 2015-07-31 14:22:03 +00:00
zzz
f3bb20d750 minor updates after review 2015-07-30 20:41:45 +00:00
kytv
20cb284f9d update geoip, bump to -23-rc 2015-07-30 17:03:46 +00:00
kytv
b4993d42b3 updated i2prouter po files (deb related) 2015-07-30 07:11:45 +00:00
kytv
9b466f3261 refresh debian patch so my automated update builds will run again 2015-07-30 06:52:18 +00:00
zzz
0bf9cb3bf2 add news cert 2015-07-28 13:55:10 +00:00
zzz
9efe60d7a8 Fix processing of translated news 2015-07-27 18:10:01 +00:00
zzz
d848a19ab0 update translations, bump -20-rc 2015-07-26 14:22:33 +00:00
zzz
bfde521cf9 NetDB: Fix NPE (ticket #1619) 2015-07-25 13:37:45 +00:00
zzz
fea6b8aec3 i2psnark: Fix total_size in metadata message (ticket #1618) 2015-07-25 13:15:56 +00:00
str4d
1681598dec merge of '30be1cda5a1ad30d33bbd355f4d85785a889c9fb'
and '8ec6b122079156e35f7515afa5eb433a13ce41b0'
2015-07-23 01:31:39 +00:00
str4d
809a533573 Updated history 2015-07-23 01:22:12 +00:00
str4d
265e4b58a5 Throw DataFormatException if not enough bytes 2015-07-23 01:15:11 +00:00
dg2-new
93854e93b5 bump -18-rc 2015-07-22 23:36:19 +00:00
dg2-new
f6605d05d9 merge of '1ba9885122d9a9ec69c77342719d8464aae244be'
and 'c61353ade089ac0e1fa83fab661dc6893b51b95a'
2015-07-22 23:34:32 +00:00
dg2-new
c20772702a I2PSnark: Don't let tunnels start unless we're starting torrents (regression, #766) 2015-07-22 22:05:44 +00:00
str4d
ba5af15c6f Fix KeyCert bug 2015-07-21 01:19:37 +00:00
str4d
9af197e590 Add KeyCert test that fails 2015-07-21 01:19:23 +00:00
str4d
2f59a4b3e6 Fix test 2015-07-21 00:40:35 +00:00
kytv
63e934f8f2 Update English PO files 2015-07-17 01:36:45 +00:00
zzz
dd5f804150 Console: Add dates to news headings
Spacing for news headings in summary bar
2015-07-16 18:06:48 +00:00
dg2-new
35b0e99ff0 I2PSnark: Fix torrent-stopping (#766) 2015-07-14 14:33:41 +00:00
zzz
1ed1e4414b Findbugs all over #4
char encoding
2015-07-12 19:19:32 +00:00
zzz
d087fd674b Findbugs all over #3
char encoding, remove FileReader/FileWriter
Fix TunnelConfig bug
2015-07-12 16:34:24 +00:00
zzz
1f9bb046f5 Findbugs all over #2
Mostly char encoding
Use StringWriter rather than OSW->BAOS->String
2015-07-12 16:06:49 +00:00
zzz
914cc120ad Findbugs all over 2015-07-12 14:02:55 +00:00
dg2-new
631a0674ab bump 2015-07-08 21:26:13 +00:00
dg2-new
17d26976d5 lang fixups 2015-07-08 21:25:33 +00:00
dg2-new
dc9d60e261 I2PSnark:
- Fix NPE (#1615, h/t kytv)
- Fix start/stop status resumption on restart (#766, h/t backup)
2015-07-08 21:22:45 +00:00
zzz
2c191e7bf8 Tunnels: New Bloom filter size, increase bandwidth limit (ticket #1505) 2015-07-08 13:40:26 +00:00
zzz
817888c23c i2psnark: Tweak dest display in footer 2015-07-07 18:42:26 +00:00
zzz
1eaf376ee7 Crypto: Check for error return from sign() 2015-07-07 13:46:04 +00:00
zzz
6cb3d1d330 Updates: New news URL 2015-07-07 13:38:44 +00:00
zzz
2681c4b42f Streaming: New config to add to DSA-only list 2015-07-07 13:35:55 +00:00
zzz
05959d5199 SSU: Request outbound bandwidth on the way into the
sender queue, not on the way out, so that SSU requests
bandwidth allocations for each packet in parallel
and competes more effectively with NTCP for bandwidth.
Inbound stubbed-out only.
2015-07-05 12:30:01 +00:00
zzz
113a8a52f3 Transport: Raise bandwidth refiller thread priority
so I/O doesn't stall under high CPU load
- Raise DH generator thread priority to keep
  DH building out of event pumper thread
- Raise PRNG and YK generator thread priorites one notch
- Set I2PThread priority in constructor
Fixes problems mainly seen on Windows, which seems
to be much more sensitive to priority settings
2015-07-05 12:08:33 +00:00
zzz
98a4460bde fix test compile 2015-07-02 15:20:58 +00:00
dg2-new
3645c906e8 merge of 'a0b025f180c1f7befcc1eb504c24140cf9e3fc0f'
and 'e0773d79a9bc8820024206f39686541ddb393c4a'
2015-06-29 20:22:10 +00:00
zzz
fcdd8be7a7 Transport: More fixes for SSU stalling -
Don't skip further bandwidth allocations for SSU, since
it needs the entire allocation to proceed.
Log tweaks
More synchronization of requests
2015-06-29 16:02:07 +00:00
zzz
34f6f65104 UPnP main() test tweak 2015-06-29 15:59:45 +00:00
zzz
4c516cd2af log tweak 2015-06-29 15:58:41 +00:00
dg2-new
8ea6805f8d Prevent double-save for now and auto start all torrents if autostart is already set (don't make the user restart each one). 2015-06-28 19:43:57 +00:00
zzz
23f2261bd9 Apache Tomcat 6.0.44 2015-06-28 12:13:52 +00:00
zzz
dd47389ad1 Console: Use registered host/port for eepsite link (ticket #1604)
Jetty starter: Register host/port when started
PortMapper: Add hostname support
2015-06-25 17:00:52 +00:00
zzz
25268e7cb2 Transport: Add failsafe to prevent complete SSU stall waiting
for bandwidth limiter, root cause unknown
2015-06-24 19:11:05 +00:00
zzz
355b2a1528 I2CP: Don't try to decrypt an LS before it's encrypted (ticket #1608)
log tweaks
2015-06-23 21:16:34 +00:00
zzz
975149d049 Router: Increase default outbound bandwidth to 60 KBps;
raise class L/M boundary to match so defaulted routers are still L
2015-06-23 20:50:22 +00:00
zzz
af394e13ad GeoIP: Add countries and flags for Asia/Pacific, Bonaire, St. Barts,
St. Maarten, South Sudan
AP: black flag copied from A1
BL: official flag is France, copied from FR
BQ, SX, SS: PNG files generated from public domain SVG files from Wikipedia
Shortened some other country names (remove "Republic of", etc.)
Change spelling to Macau, Vietnam
2015-06-23 20:33:38 +00:00
zzz
e3f64f6edf Console: Fix NPE on /configtunnels 2015-06-23 20:26:02 +00:00
dg2-new
2fbbfa388e NetDB: Partially revert last NetDB change: flood because we don't want to create a hole in the DHT before publisher resends to somebody else. 2015-06-22 20:11:29 +00:00
zzz
0b4d4ddcbc update hardcoded tags 2015-06-21 15:42:30 +00:00
zzz
428d89a307 Update: Add config to disable translated news
Rewrite addLang() for efficiency
2015-06-21 15:41:33 +00:00
dg2-new
feff6c003b bump 2015-06-20 10:30:14 +00:00
dg2-new
699d550992 NetDB: Don't say we stored, and don't flood, if we're shutting down 2015-06-20 10:06:54 +00:00
dg2-new
c6896c4418 I2PSnark: Auto-start now only starts torrents which were running at shutdown (#766) 2015-06-20 10:03:47 +00:00
zzz
1b2d4c75eb I2CP: Fix simple session lookups, broken in prop 2015-06-19 15:55:07 +00:00
zzz
586defc802 Tunnels: Increase default max tunnels 2015-06-19 14:57:59 +00:00
zzz
2499aad51d I2PSocketEepGet: Do hostname lookups in-session for efficiency 2015-06-19 14:55:49 +00:00
zzz
addb142ecd I2CP: Move client-side implementation classes to
new package net.i2p.client.impl, leaving only the
factories and interfaces in net.i2p.client
2015-06-18 21:20:00 +00:00
zzz
20c796e87a Update: Add language param to news fetch, to support translated news (ticket #1425) 2015-06-18 15:05:48 +00:00
zzz
cd62d7170c I2CP: Don't send the first LS request to the client until we have
at least one OB tunnel, so the client waits until we are ready.
This will reduce drops, retransmissions, and failures on new client tunnels.
Fixes to prevent multiple pending LS requests.
2015-06-18 15:02:21 +00:00
kytv
acc647822f sync debian changelog in mtn 2015-06-18 10:34:54 +00:00
zzz
1cf544f1d4 fix unit test compile 2015-06-18 00:41:58 +00:00
zzz
0f4e09500c javadocs 2015-06-17 23:46:11 +00:00
zzz
7c5dfaee20 I2CP: More fixes after prop, w.r.t. restore after close-on-idle
- When socket is closed, set sessionID and LS to null,
    close subsession and set its sessionID and LS to null
  - Checks on client side for null session ID
  - Check for null session in Destroy Session message
  - Don't kill I2CP connection due to a bad session ID
    in a SendMessage, just drop the message and send
    a MessageStatusMessage
  - Log tweaks
2015-06-17 23:44:12 +00:00
zzz
8d9cced128 history for prop, -6 2015-06-17 16:17:46 +00:00
zzz
8096e4f65d propagate from branch 'i2p.i2p.zzz.multisess' (head 655a0c2bbd50625c804b8de8c809b40ed63f53f4)
to branch 'i2p.i2p' (head b977ab50209475c0e74825f361924e05dbd470c7)
2015-06-17 16:00:53 +00:00
zzz
036b77746b Catch uncaught exceptions in ClientConnectionRunner and stop connection
Catch null SessionId in messages and stop connection instead of NPE
Wait for LS in SubSession in connect() so we don't send data w/o
a session ID and leaseset
Log tweaks
2015-06-17 02:16:06 +00:00
zzz
bc85543ef2 Fix removal of subsession aliases from tunnel manager on
I2CP connection shutdown
Sort tweaks for shared clients in summary bar
2015-06-15 14:35:15 +00:00
kytv
627f7076b0 debian: Add support for setting open file limits to initscript, add comment to explain how to do it with systemd 2015-06-14 20:16:16 +00:00
kytv
863e120204 Hard-depend on gmp >> 5. 2015-06-14 20:12:00 +00:00
kytv
53cfba4cbd merge of 'cb89dec5190f295ba301666166448929f1b7f3c1'
and 'f13d8499995c44dc76ae61d4b5c4c936e307eb89'
2015-06-14 20:07:43 +00:00
kytv
3a774b7c37 Rename i2p.mooo.com2.crt to i2p.mooo.com.crt, certificate has been switched out on the server 2015-06-14 20:07:35 +00:00
zzz
0ad34a4b00 Timestamper: Reduce NTP timeouts to shorten startup time
when NTP is blocked
2015-06-13 16:25:58 +00:00
zzz
2b9ffc1270 javadoc fixes after review 2015-06-13 15:14:21 +00:00
zzz
93c7860d2b NetDB: Improve routing of DatabaseStoreMessage acks
Send our own RI unsolicited in reply if we aren't floodfill
  Don't ack or flood a store of an unknown type
PeerTestJob: Don't generate zero reply token
Tunnels: More checks of messages received down exploratory tunnels
javadocs and comments
2015-06-13 15:13:35 +00:00
kytv
25f6c3d9e1 apparmor: tweaks to TMPDIR rules 2015-06-13 15:05:28 +00:00
zzz
b9e07bc9aa i2psnark: Fix NPE (ticket #1602) 2015-06-13 14:20:08 +00:00
zzz
09f68e44ca enable ECDSA by default for shared clients 2015-06-10 23:24:38 +00:00
zzz
013b5fd85b more @since updates 2015-06-10 19:24:20 +00:00
zzz
8962bfb6bc more @since updates 2015-06-10 19:23:26 +00:00
zzz
605602e001 @since updates 2015-06-10 19:15:01 +00:00
zzz
f341e5566b Pass session in connect();
Store the session in Connection;
Don't create a new ConnectionManager for a subsession,
now that all components track the session properly.
@since updates
2015-06-10 19:14:33 +00:00
zzz
7b84676f4a remove session ref from PacketQueue 2015-06-10 12:37:19 +00:00
dev
c666f8a4f9 Javadoc fixes. 2015-06-09 14:30:42 +00:00
dev
e067761947 Added a new flavour of checkAvailable() to UpdateManager interface. 2015-06-09 03:57:44 +00:00
dev
226bee64ef Added more variants of isUpdateInProgress to UpdateManager. 2015-06-09 03:44:34 +00:00
dev
1a40e57413 Added isUpdateInProgress() to UpdaterManager interface. 2015-06-09 03:32:33 +00:00
dev
f73101b014 Added checkAvailable(), update() and getStatus() to UpdateManager interface. 2015-06-09 01:09:23 +00:00
zzz
fef65c996f Store the session in Packet, so we may more easily and efficiently
handle multisession, especially on the incoming side.
More refactoring to follow
2015-06-08 22:18:14 +00:00
zzz
cbc2f899a6 fixup after prop 2015-06-08 22:14:49 +00:00
zzz
099515adff propagate from branch 'i2p.i2p' (head 1de143fff53bb56e6eac926d6293d62200f0c392)
to branch 'i2p.i2p.zzz.multisess' (head 70fc07857232668b93ca6ba02c433dffc7639132)
2015-06-08 21:50:42 +00:00
dg2-new
ff2ea9ac3e Irc{Outbound,Inbound}Filter:
- Silence 'no streams' warning when we can't connect to an IRC server. Change to WARN.
2015-06-08 19:35:18 +00:00
dg2-new
97aeecd865 FloodfillMonitorJob, FloodfillRouterInfoFloodJob:
- Directly connect to nearby floodfills to share our RI to speed up integration of new floodfills (#1195).
- Called on both non-ff -> ff OR ff -> non-ff.
- Create FloodfillRouterInfoFloodJob to do so.
2015-06-08 19:24:28 +00:00
dg2-new
8098d705f9 Make netDb.storeFloodNew graphable for testing (#1195) 2015-06-08 16:39:41 +00:00
dg2-new
fa8c390267 Language fixups. 2015-06-08 16:14:08 +00:00
zzz
e8f4e19bac NetDB: Fix early NPE 2015-06-07 16:29:41 +00:00
zzz
9041a2c69f SSU: Possible fix for NPE in establisher 2015-06-07 14:13:58 +00:00
zzz
384e9118c6 Logs: Correct wrapper.config location when running as a Linux service 2015-06-07 12:44:29 +00:00
kytv
0936a2ee23 disable 193.150.121.66 (ticket #1596) 2015-06-06 21:36:24 +00:00
kytv
bc6b0c12ac update debian changelog to reflect the latest release 2015-06-06 21:33:51 +00:00
kytv
f6f051cfa4 remove unneeded user-tmp abstraction; tighten tmpdir perms 2015-06-06 21:31:38 +00:00
zzz
fb131a040c fix snark sort by rate of stopped torrents 2015-06-06 20:54:13 +00:00
zzz
9f2ded6073 cleanup 2015-06-06 20:53:33 +00:00
zzz
55e36ee458 Console: Add indication of current ff status on /configadvanced,
change immediately when config changes, force republish
Router: RI rebuild locking
2015-06-06 16:01:39 +00:00
str4d
7c13fb2ba0 Android's SimpleDateFormat doesn't support XXX at any API 2015-06-06 09:24:46 +00:00
str4d
663ccb72d7 Bump router version 2015-06-05 01:53:52 +00:00
str4d
78e0a37fc9 Define I2PTunnelClientBase stats in one place 2015-06-04 22:36:45 +00:00
str4d
09cdc00939 i2ptunnel: Don't call startup() in chained constructor (ticket #1593) 2015-06-04 22:34:13 +00:00
str4d
2590e7d4ff i2ptunnel: Don't connect manager to router in constructor (ticket #815) 2015-06-04 22:25:44 +00:00
zzz
27f56776ca Console: Fix display of n/a for events that never happened on floodfill profiles 2015-06-03 20:45:15 +00:00
zzz
657f13af29 Remove ConnectionManager ref from PacketQueue 2015-06-03 17:25:25 +00:00
zzz
e2ca74963f Console: Click on version or country in /netdb table to get list of those routers 2015-06-03 16:55:01 +00:00
zzz
9304cb2bbc SAM message quoting fix 2015-06-03 12:33:42 +00:00
zzz
362086994a history for props, -1 2015-06-03 12:03:07 +00:00
zzz
f57e37d588 comment fix 2015-06-03 12:02:25 +00:00
zzz
d96ddd1a0e propagate from branch 'i2p.i2p.zzz.sam' (head 68de14d0053dea374413f9e0419b1c0f7e9ec3af)
to branch 'i2p.i2p' (head 54f5dd288f7c0c5a50f7f63f911aec4008be27e2)
2015-06-03 11:42:54 +00:00
zzz
7b711ebba0 propagate from branch 'i2p.i2p.zzz.test2' (head 47586aa88408845c51ee4c5fce40c617bdb8e398)
to branch 'i2p.i2p' (head bacb6048bc596f064ff237dd8569014a421b4ef6)
2015-06-03 11:40:28 +00:00
zzz
0762715264 i2psnark: Don't lose sort param when hiding peers 2015-06-02 21:04:12 +00:00
zzz
8a69dc0a97 only log reseed network disconnected warning once 2015-06-02 20:44:10 +00:00
zzz
39dc60cf8a only log UPnP network disconnected error once 2015-06-02 20:19:46 +00:00
zzz
09e867b194 i2psnark: Don't say 'download finished' unless we downloaded something
atomics
2015-06-02 20:14:33 +00:00
zzz
dc9256f274 Console: Prevent bad line-wrap of very long menu items 2015-06-02 16:41:04 +00:00
zzz
272f63dbbd Console: Nicer "move" icons on /configsidebar, add tooltips
Icons from silk, rotated, same license as before
2015-06-02 16:30:35 +00:00
zzz
06104118d0 EepGet: Recognize 418/420 responses 2015-06-02 15:44:17 +00:00
zzz
525ec01c1e Console: Don't allow unbanning of all-zero hash 2015-06-02 15:41:42 +00:00
zzz
f8594c316f DataHelper: make formatDuration() days to years be monotonic 2015-06-02 15:36:19 +00:00
zzz
3c89bd4e19 0.9.20 2015-06-02 12:00:59 +00:00
zzz
1f8408f417 Stats: Reduce number of rates in required stats to save memory 2015-05-31 14:03:39 +00:00
zzz
915b35f0c1 LogWriter: Write dup message to wrapper log and crit buf also 2015-05-31 13:22:36 +00:00
zzz
4521156ecb Fortuna: Catch AIOOBE (ticket #1576) 2015-05-31 12:43:06 +00:00
zzz
c58fd8f84e i2ptunnel: Fix +/- variance config (ticket #1587) 2015-05-30 15:46:37 +00:00
zzz
f02b401b7a SSU: More synchronization in PeerState 2015-05-30 14:25:40 +00:00
zzz
4fdcb6ce29 I2CP: Prevent sending lookup or bw limit messages before handshake with router is complete 2015-05-30 14:13:13 +00:00
zzz
94824e4d2b I2CP: Prevent sending data message before handshake with router is complete 2015-05-30 14:02:38 +00:00
zzz
280fc05c91 susidns, addressbook: Don't attempt to fetch subscriptions if
HTTP proxy is down (ticket #1530)
2015-05-30 13:53:56 +00:00
zzz
89745f5002 HTTP Client: Greatly simplify decompression by using
InflaterOutputStream, available since Java 6.
Removes PipedInputStream, PipedOutputStream.
Removes Pusher threads.
Remove delay workaround for truncated pages, no longer required.
2015-05-30 13:19:29 +00:00
zzz
7715e6484c Router: Add gzip caches to clearCaches() 2015-05-30 11:18:04 +00:00
zzz
c807194e93 propagate from branch 'i2p.i2p' (head 07028378508ab46278d193039b97c543d12ee22e)
to branch 'i2p.i2p.zzz.test2' (head 0074b91cb9fe0ed875457dc0bf1989df03fa9e9a)
2015-05-30 11:16:00 +00:00
zzz
3602f73497 HTTP client: Fix occasional truncation of compressed responses
log tweaks
2015-05-29 17:37:58 +00:00
zzz
4bf115b5f6 javadoc 2015-05-27 21:07:56 +00:00
zzz
7ab85a0a20 Graphs: prevent NaNs if we are skewed ahead of system time 2015-05-27 21:05:44 +00:00
zzz
fba0372339 Banlist: Ban all-zero hash
NetDb: Drop all-zero lookups and stores, add stats
SSU:
 - Fix debug logging of dumped packets
 - Drop sessions with bad clock skew, banlist peer, add stats
 - Drop sessions with corrupt DSM, banlist peer, add stats
Log tweaks
2015-05-27 21:00:46 +00:00
zzz
03dfa6515b SSU: send destroy message in a couple cases where we previously just called dropPeer() 2015-05-27 20:54:22 +00:00
zzz
5e33ed1169 log tweaks 2015-05-27 20:52:00 +00:00
zzz
11ab7fc56c add comment 2015-05-27 20:51:01 +00:00
zzz
716bff41d7 remove cast 2015-05-27 20:50:29 +00:00
zzz
1d8842cfc8 Gunzip: Add tests to main() 2015-05-27 20:49:51 +00:00
zzz
042b03d6b8 DataHelper: Add year output to formatDuration() 2015-05-27 20:48:51 +00:00
kytv
ab753651b9 Add new reseed server
Thanks parg!
2015-05-26 20:55:44 +00:00
zzz
4ea99b8a10 I2CP: Take 2 of fix, so a newly created session
isn't destroyed and immediately replaced by i2ptunnel,
which caused dup shared clients in a race at startup;
Clarify session exception text if not open
2015-05-24 00:14:32 +00:00
zzz
3d07e1a10b I2CP: Revert part of prior checkin, prevented idle tunnel from opening;
(treat INIT as CLOSED) better fix to follow
2015-05-23 20:02:46 +00:00
zzz
86525e7239 i2ptunnel: Strip top-level supercookies too 2015-05-23 17:13:15 +00:00
zzz
195171f9ed I2CP: Add an INIT state for session, so a newly created session
isn't treated as CLOSED and immediately replaced by i2ptunnel,
which caused dup shared clients in a race at startup
(possible related tickets #642, #650, #815, #1545)
2015-05-23 16:07:49 +00:00
kytv
33c4be5b2f Updates to geoip.txt and geoipv6.dat.gz based on Maxmind GeoLite Country database from 2015-05-06. 2015-05-21 17:32:35 +00:00
kytv
fea2c3c6b2 Install the apparmor profiles in complain mode
Instead of enabling exceptions when needed for custom set-ups, some users will
opt for disabling all security functions.
2015-05-21 17:27:29 +00:00
kytv
281686ba58 clarify comment 2015-05-21 17:24:32 +00:00
kytv
0b91fcb636 sync Translations with Transifex 2015-05-21 17:11:50 +00:00
kytv
807f1381fb sync debian/changelog 2015-05-21 16:54:35 +00:00
kytv
ac56a63809 remove /dev/(u)?random since these are included in the base abstraction 2015-05-21 16:52:09 +00:00
kytv
e4798b9ed8 allow user scripts installed to cgi-bin to be executed 2015-05-21 16:46:19 +00:00
kytv
7584346c82 fix indentation of i2p abstraction 2015-05-21 16:44:00 +00:00
zzz
29330aa5d3 i2psnark: Another place to send reject; switch to LBQ 2015-05-19 23:21:18 +00:00
zzz
65ff2c0afe i2psnark: Log tweaks and cleanups after testing 2015-05-19 21:56:21 +00:00
zzz
de4d47de95 i2psnark: Add support for fast extensions (BEP 6)
untested
2015-05-19 18:13:32 +00:00
zzz
ae41a3f316 SSU:
Synchronize UDPPacket methods, possible fix for bad
packets and UDP stalls caused by cache corruption?
Cleanup unused methods and fields
2015-05-19 14:49:02 +00:00
zzz
2dc3d68418 propagate from branch 'i2p.i2p' (head d046bffcd4f94b253e1aa2bfc9a90482974363dd)
to branch 'i2p.i2p.zzz.test2' (head d00c6fd9c9aef6c37218a791a12f2da957181cd2)
2015-05-18 11:09:26 +00:00
zzz
5eb43b6ae4 Translate: Clear ResourceBundle cache too,
available since Java 6 / Android API 9
2015-05-18 11:08:40 +00:00
zzz
0c672ecc49 Update: Fix NPE in initialization 2015-05-16 13:10:07 +00:00
dg2-new
3b6d98fe38 Translate "Dest" instead of "Dest:", tabbing (thx zzz) 2015-05-15 22:36:49 +00:00
dg2-new
b3472cfe80 Show the I2PSnark dest on the main page (#1436) 2015-05-15 20:51:45 +00:00
dg2-new
38f2b93c7a typo 2015-05-15 20:30:59 +00:00
zzz
e7af87a981 Update: Ignore su3 dev build version at startup if older 2015-05-15 19:15:51 +00:00
zzz
d698a67660 Deprecate Router.setConfigSetting() and removeConfigSetting() 2015-05-15 15:50:16 +00:00
zzz
b38f2d62a8 bump -23 2015-05-15 14:58:54 +00:00
zzz
10556bca75 merge of '174649506cd8a9665ad798c090e39481af967011'
and '67eb724b7638284d33f1b4997183cc9f197d2883'
2015-05-15 14:17:41 +00:00
zzz
1f17d2a149 add cacapo plugin cert 2015-05-15 14:17:08 +00:00
dg2-new
dc777c8de5 fix on non-full stats routers (thx zzz)
doh
2015-05-15 13:42:16 +00:00
zzz
1fb9643916 i2psnark: Fix deletion of single-file torrent outside snark dir (ticket #1544) 2015-05-13 14:00:19 +00:00
zzz
081f1865a8 Console: Fix URLs caught in XSS filter on /confighome (ticket #1569)
Fix name and URL escaping
Truncate long URLs in display
2015-05-13 12:04:28 +00:00
zzz
0e17c560b3 NTCP: Catch race in Reader (ticket #1534) 2015-05-13 10:52:26 +00:00
zzz
a3b1327934 javadoc fixes 2015-05-13 10:48:48 +00:00
zzz
e68ca573f0 remove status message 2015-05-13 10:41:49 +00:00
zzz
b5455cee6e SAM: Set keepalive on sockets (ticket #1573)
Also on both sides of I2CP.
BOB already does it.
2015-05-12 20:13:17 +00:00
dg2-new
cbdc1403bf remove old check
bump
2015-05-12 19:53:19 +00:00
zzz
40130a8a61 SAM:
- Close sockets and stop tunnels when router-side SAM stops (ticket #1572)
- Better checks for quoting status message strings (ticket #1488)
- Set encoding for sam.keys file
- Don't throw NPE on rare stream errors
- Comment out unused dumpProperties()
- Cleanups, log tweaks, thread name tweaks
2015-05-12 19:07:42 +00:00
dg2-new
ca14055976 fix build 2015-05-12 19:02:00 +00:00
dg2-new
8303016b48 - Job Queue/stats: add stat/graph for amount of scheduled jobs (router.tunnelBacklog)
- FloodfillMonitorJob:
  - Use avg of router.tunnelBacklog instead of current backlog
- Some language/spelling fixes
2015-05-12 18:46:40 +00:00
kytv
287862887d runplain.sh improvements 2015-05-11 01:12:13 +00:00
zzz
f25d2a3d3f Util: Fix corruption of cached ReusableGZIPInputStreams,
caused by calling close() from HTTPResponseOutputStream.Pusher,
but close() rendered the underlying InflaterInputStream unusable.
Broken in -15. Caused failed HTTP fetches and other flakiness.
2015-05-11 00:08:26 +00:00
zzz
7f30f481b2 i2ptunnel: Improve error handling for UDP tunnels,
Sink.send() may now throw RuntimeException,
converted from IOException or I2PSessionException;
interrupt runner threads on error;
ignore I2PSessionException in Pinger.close();
logging and javadoc improvements;
untested
2015-05-09 22:22:13 +00:00
zzz
5ee6826241 Plugins: Add support for custom icons (ticket #1550) 2015-05-09 15:28:43 +00:00
zzz
68951c4c6b remove http in linkify() 2015-05-09 13:19:46 +00:00
zzz
5dc7497802 Reseed: Don't reseed while shutting down (ticket #1565) 2015-05-08 12:27:40 +00:00
zzz
31cfddc218 Router: Clear I2CP lookup cache on exit 2015-05-07 16:46:15 +00:00
zzz
c1e70ac7d2 SAM: Close datagram or raw session when underlying
I2P session closes (ticket #1563)
2015-05-07 16:04:08 +00:00
zzz
dd9abd3f09 set installed dev version 2015-05-07 14:18:47 +00:00
zzz
2f5e64e532 Update: Add support for su3-signed development builds (ticket #1381)
Full version is used as the su3 version.
Uses same su3 certs as release updates. Users may add additional certs
to ~/.i2p/certificates/router/ as necessary.
Copy echelon's reseed key for use as a router signer.
Unsigned update remains a separate option for now.
Various update subsystem cleanups.
2015-05-07 13:04:43 +00:00
zzz
b12f988390 javadoc fixes 2015-05-07 13:03:17 +00:00
kytv
9f3d5bf57b use the full version string (including build number) in the signed-* build targets 2015-05-06 23:24:08 +00:00
zzz
7f9e958e5a Datagram: Convert IOE to DFE and throw on datagram load error
rather than failing silently
2015-05-06 20:05:30 +00:00
zzz
c4877ea092 Crypto: Comment out Cryptix debug logging 2015-05-06 01:53:50 +00:00
zzz
2aafc23774 PrintWriter doesn't throw exceptions, so call checkError() 2015-05-06 01:51:57 +00:00
zzz
77c9a644ac Naming services: Export address books with Windows line endings on Windows (ticket #1557) 2015-05-06 01:48:47 +00:00
zzz
abd8ca34dc Transport: Add config to force IPv4 (only) to firewalled (ticket #1541)
since we cannot reliably detect DS-lite (ticket #1458)
Hide transport status on /peers unless routerconsole.advanced
2015-05-06 01:45:33 +00:00
dev
31435685bf Added disclaimer about not being a part of the public API. 2015-05-05 22:16:51 +00:00
zzz
7337fd0670 i2ptunnel: Add Connection: close headers to errors and proxy.i2p responses
where it was missing (ticket #1531)
2015-05-04 16:36:49 +00:00
zzz
f7b7a98b9d i2ptunnel: Close input stream when HTTP client decompressor terminates (ticket #1506)
streaming: Minor cleanups, log tweaks
2015-05-04 14:43:54 +00:00
kytv
2226936737 i2prouter 'console' bugfix: Don't report failure for INT signal 2015-05-04 14:10:25 +00:00
kytv
8b293b2190 symlink instead of copying
I created this patch a couple of years ago and at that time symlinking (for
reasons I don't remember anymore) didn't work. Now it works with symlinks, so
let's go with that. (Tested in OpenBSD 5.7)
2015-05-04 13:47:32 +00:00
zzz
94bba8d11f I2CP: Fix external I2CP SendMessageExpires, broken in previous cleanup 2015-05-04 12:36:03 +00:00
kytv
5c2b5075f9 support OpenBSD in i2prouter
We don't include a wrapper for OpenBSD and Tanuki doesn't offer OpenBSD
binaries either. It is available as an OpenBSD package. Therefore, if the
wrapper is not found (likely), advise the user to install it. The next time
`i2prouter start` is run, the wrapper will be copied to the I2P install
directory and it should "just work".
2015-05-04 09:22:25 +00:00
kytv
ca6820a4c0 refresh debian patch 2015-05-04 00:26:26 +00:00
zzz
2fafa3337f Console: Add floodfill configuration form to /configadvanced 2015-05-03 18:49:34 +00:00
zzz
b5f75a4bb9 Router: Allow class M to become floodfill;
add bandwidth classes P and X (ticket #1447)
2015-05-03 17:35:09 +00:00
zzz
707bfbbf8b Router: Put the GarlicMessageParser in the RouterContext
to reduce object churn, we only need one
Add DeliveryInstructions.create() to return immmutable
local instructions, to reduce object churn
Minor cleanups
2015-05-03 17:00:22 +00:00
zzz
1eba6c5167 SusiDNS: Add export button 2015-05-03 13:21:16 +00:00
zzz
a14208b841 Move Indonesian po files used by Java om _id to _in, since
Locale.getDefault().getLanguage() will only return "in".
See Locale javadocs. Same change already made in Android.
2015-05-02 23:23:13 +00:00
kytv
83966f9a7f Switch out the certificate for netdb.i2p2.no, replacing it with a stronger one
certificates/ssl/netdb.i2p2.no2.crt was checked in on 2014-12-08 with the
intention of its replacing certificates/ssl/netdb.i2p2.no.crt after a
transition period of a few months had passed. The certificate has already been
switched out on the server.
2015-05-02 20:49:50 +00:00
zzz
d89f06015b merge of '7cc7b74d018c5e2d5d571000d066e65ad034c114'
and 'd87b6870e67271b703a38f82cb6fc9b753bf9698'
2015-05-02 17:46:48 +00:00
zzz
49f786c928 Transport: Ticket #1458 continued...
enum fixes so we don't always force a peer test quickly
set reachability status at startup when interfaces are configured
prevent firewalled -> OK -> firewalled+OK transition
2015-05-02 17:45:37 +00:00
zzz
e8bc0bd5d1 Stats: randomize router count at startup also 2015-05-02 17:42:49 +00:00
kytv
8d69b69357 Switch out the certificate for ieb9oopo.mooo.com
certificates/ssl/ieb9oopo.mooo.com2 was checked in on 11/23/2014 with the
intention of its replacing certificates/ssl/ieb9oopo.mooo.com.crt after a
transition period of a few months had passed. The certificate has already been
switched out on the server.
2015-05-02 15:59:33 +00:00
kytv
e7b9a230e6 add 'bump' as an alias for the 'bumpBuild' ant target 2015-05-02 15:50:25 +00:00
kytv
6385c412fd Disable https://jp.reseed.i2p2.no:444/ due to extended downtime, unresponsive host (ticket #1422) 2015-05-02 15:48:46 +00:00
zzz
bb33b358b4 Change log level for Jetty warnings with exceptions
from error to warn (ticket #1551)
2015-05-02 14:36:39 +00:00
zzz
572f071cfe Jetty 8.1.17.v20150415 2015-05-02 14:09:59 +00:00
zzz
42cb89f525 bump -12 2015-04-30 21:14:56 +00:00
zzz
1868d2b50f Transport: Ticket #1458 continued...
Implement methods to remove only a single IPv4 or IPv6 address,
so that IPv6 addresses will remain when SSU detects that IPv4 is firewalled
Summary bar status fixes
Fix getIsPortFixed() for more enum cases
log tweaks, cleanups
2015-04-30 20:33:46 +00:00
zzz
4588f1ec75 I2CP: Periodically send a SetDate message to external clients
so they stay in sync
2015-04-29 15:22:55 +00:00
zzz
629f7f05c7 Transports: Track IPv4/v6 reachability separately (ticket #1458)
Don't include NTCP conns established too long ago in clock skew vector
Hide unestablished outbound NTCP conns from /peers view
Add per-transport status to /peers
Put status description instead of code into event log reachability changes
2015-04-29 12:50:33 +00:00
zzz
0f18686243 Clock: Make forward slewing work better
when now() is not called too frequently
2015-04-29 11:48:17 +00:00
zzz
2a2587b13d fix logic bug 2015-04-29 02:41:25 +00:00
zzz
489fdd5e4b NTCP: Use context time, not system time, in NTCPConnection
so that clock skew calculations work right
2015-04-29 02:35:22 +00:00
zzz
fe680eb192 Transports: Fix clock skew calculations
- NTCP inbound skew calculation had flipped sign
- Include RTT in NTCP skew calulation
- Set SSU skew on first packet so it's right from the beginning
- Above should fix the "ignoring clock offset" error
- Javadocs
RouterClock:
- Add config to disable clock adjustment for testing
- Reduce window in skew vector for slew calculation
- Double max slew rate
2015-04-29 01:30:33 +00:00
zzz
613440ff63 CSF: New enums for SNAT/OK and SNAT/UNKNOWN 2015-04-28 22:26:40 +00:00
zzz
64121b1e92 catch OOM in the OOM listener 2015-04-28 22:24:05 +00:00
zzz
f16927f316 JobQueueRunner: Don't call System.exit() on OOM,
let the shutdown progress normally;
Make it an I2PThread instead of a Runner so we can
call fireOOM() for consistent logging (ticket #1549)
Router: Don't add OOM listener on Android so
we don't hang onto the context
2015-04-28 21:57:13 +00:00
zzz
cb50c1bd8b improve UDP test 2015-04-28 12:44:53 +00:00
zzz
921ad86274 Comm System: More prep for ticket #1458
- Big method to handle status transitions, not yet used
 - Status enum tweaks, unknown must be higher code than known
2015-04-28 03:25:20 +00:00
zzz
ac76107752 Transports:
- More transition to status enum
 - Don't set TCP keepalive for IPv6
2015-04-28 03:21:28 +00:00
zzz
2359b1edd2 Transports: Convert internal state to enums (ticket #1458) 2015-04-27 17:05:16 +00:00
zzz
2750681d78 CommSystem: Stubs for separate IPv4/v6 status (ticket #1458) 2015-04-27 15:44:05 +00:00
zzz
eaac4d3de0 NamingService: Add export methods,
fill in subclass methods for efficient exporting,
fill in getBase64Entires() and getNames() where unimplemented
SusiDNS: Add export support, no UI yet
2015-04-27 15:41:38 +00:00
zzz
f243968dfa i2ptunnel: Reduce sleep time in runners to reduce latency
greatly improves "loopback" performance
minor cleanups
2015-04-26 17:50:06 +00:00
zzz
8d9e2bdc71 log tweaks 2015-04-26 17:46:48 +00:00
zzz
6dbbb6b61b minor cleanup 2015-04-26 17:46:14 +00:00
zzz
f89bf32390 target=_top 2015-04-26 17:45:31 +00:00
zzz
ef195aa4ef re-add fixed reseed 2015-04-26 17:45:01 +00:00
str4d
843230a1cb Fixed MessageInputStreamTest after constructor changes 2015-04-26 01:43:34 +00:00
zzz
84e63f3b38 reseed tweaks for SNI 2015-04-26 00:12:17 +00:00
zzz
b90816fdf8 add package.html files 2015-04-25 23:15:52 +00:00
zzz
40c4a42921 I2PSSLSocketFactory:
- Add hostname verification using code from
Apache HttpClient 4.4.1 (Apache 2.0 license)
and one small class from HttpCore 4.4.1,
slightly modified to remove additional Apache dependencies
and unneeded code.
- Includes support for public suffix list;
use basic list with standard TLDs,
and also support loading the big Mozilla list,
but don't bundle the 150KB Mozilla list for now.
- For Android, use its default verifier, which
should actually work (unlike Oracle)
- Java 7 not required, although servers requiring SNI will now
fail on Java 6, which does not support SNI
SSLEepGet:
- Rework recent setSoTimeout code changes, as they broke SNI
- Add option to save certs even if no errors
- Add option to disable hostname verification
2015-04-25 23:06:44 +00:00
zzz
26f89391d3 Mods to remove additional Apache dependencies
and unneeded code, now compiles
2015-04-25 22:56:51 +00:00
zzz
aaae72cf84 - Initial checkin of Apache classes from
Apache HttpClient 4.4.1 (Apache 2.0 license)
and one small class from HttpCore 4.4.1,
unmodified as a baseline for future merges.
Does not compile.
See following checkins for more info
2015-04-25 22:54:05 +00:00
zzz
3e55cff153 Util: Catch and convert OOM in I2PThread.start() to a RuntimeException,
to give better message to users and prevent JVM shutdown
on what is unlikely to be a heap issue.
2015-04-25 00:02:55 +00:00
zzz
bd778a2204 Remove old pre-0.6.1.30 TunnelCreateMessage and TunnelCreateStatusMessage,
moved to junit years ago but not part of any tests
2015-04-24 22:25:17 +00:00
zzz
235c196f14 log tweaks 2015-04-24 21:37:22 +00:00
zzz
e475c161cb i2ptunnel: Don't register port mapper in clients overriding startRunning()
if super.startRunning() failed
Register as HTTPS proxy also in HTTP client
2015-04-24 21:16:45 +00:00
zzz
08e96109a7 i2ptunnel: Fix shutdown of client tunnels on server socket errors,
broken in fix for ticket #815
TCG still doesn't go back to stopped, to be fixed.
Test case: configure low port.
2015-04-24 19:19:18 +00:00
zzz
81ad33d9e3 lint unchecked 2015-04-24 16:27:03 +00:00
zzz
aecc95825b Updates: Fail fast if HTTP proxy is not running (ticket #1530)
Covers router, unsigned router, plugin, and news updates
2015-04-24 16:08:08 +00:00
zzz
37c6ac3a88 i2ptunnel: Fix Socks and SocksIRC tunnels not starting,
broken in fix for ticket #815
2015-04-24 01:48:07 +00:00
zzz
772d0beac3 Streaming: Don't wait too long to send a dup ACK, so the other
side isn't stuck forever at a window size of 1.
Cleanups, log tweaks, javadocs
2015-04-23 15:34:24 +00:00
zzz
64fdfd81ee remove excess logging 2015-04-23 13:38:44 +00:00
zzz
1b09b9faa4 Streaming: More efficient checking for input buffer overflow,
add additional checks.
Fix bug if available buffer calculation is negative
Check log level before calling displayPacket()
Log tweaks
2015-04-23 13:19:18 +00:00
zzz
6f0ebb2d94 Streaming: Reduce min RTO so that "loopback" connections
recover quicker after packet loss;
Reduce default initial ack delay;
Rename misspelled method
2015-04-23 10:28:02 +00:00
zzz
cbe91e3012 I2PSocketEepGet: Fix i2psnark NPE caused by -6 (ticket #1543) 2015-04-22 20:34:04 +00:00
zzz
238501919b i2psnark: Fix deletion of config files, cleanup
orphaned ones at startup (ticket #1498)
2015-04-22 20:22:17 +00:00
zzz
ae3a5f7b25 name tunnel starter threads 2015-04-22 20:17:33 +00:00
zzz
638cadc3c9 NetDB: Disable floodfill for non-ARM Android also 2015-04-22 15:54:18 +00:00
zzz
da0036581c thread name tweak 2015-04-22 14:51:40 +00:00
zzz
59a58ea310 NTCP: Reduce min send finisher threads to 1 2015-04-22 14:48:59 +00:00
zzz
bebe5f8a4e PortMapper: Status output for /debug 2015-04-22 14:45:40 +00:00
zzz
c3af99685d log tweak 2015-04-22 12:00:46 +00:00
zzz
e1d9e05b8d i2ptunnel: Fixes and cleanups for command line testing;
catch IAE from getInstance() if i2ptunnel.config isn't found
in app context; log tweaks; config command tweaks
Unit tests: Fix several NPEs in LocalClientManager,
implement HostLookup
2015-04-22 11:59:40 +00:00
zzz
212f6b472a i2ptunnel: Catch and log uncaught errors in thread pool 2015-04-21 20:37:59 +00:00
zzz
fdada78edf Reseed: Disable non-su3 reseeding 2015-04-21 18:48:11 +00:00
zzz
638c5429d2 NTP:
- close socket in finally
 - really comment out main()
2015-04-21 14:49:48 +00:00
zzz
b67bbd7065 improved locking 2015-04-21 14:33:59 +00:00
zzz
1caf3e778b Router timestamper:
- Add country-to-continent mapping
 - Add continent pool.ntp.org zones as first fallback,
   this will improve time service for countries that don't have a zone
 - Don't start threads in constructors
 - Fix logging, better prevention of initialization loops
 - Log severe errors to wrapper log also
continent.txt file from http://dev.maxmind.com/geoip/legacy/codes/country_continent/
Creative Commons Attribution-ShareAlike 3.0 Unported License
http://dev.maxmind.com/geoip/legacy/geolite/
Terms already met in LICENSE.txt
2015-04-21 14:22:05 +00:00
zzz
fd82fff07a Transports: Reduce idle timeouts 2015-04-21 09:58:46 +00:00
zzz
a6ac8f8c09 Blockfile: Unroll recursive initialization of BSkipLevels 2015-04-20 22:56:08 +00:00
zzz
19a26f8e22 Reseed: Prep for disabling non-su3 fetches (ticket #1513) 2015-04-20 18:48:00 +00:00
zzz
46e85cf265 only reset the sotimeout if not proxied 2015-04-20 17:57:57 +00:00
zzz
8f321b5427 EepGet: Set soTimeout for non-proxied fetches to enforce
header timeout and prevent long reseed hangs
2015-04-20 17:53:29 +00:00
zzz
e1f8f1a3f4 Reseed: Remove all default HTTP URLs (ticket #1514) 2015-04-20 16:11:33 +00:00
zzz
935a5b573d Reseed: Better error message if no valid URLs for configuration 2015-04-20 15:45:49 +00:00
zzz
8c2636aa99 Reseed: Honor SSL/non-SSL setting when custom reseed list is set (ticket #1136)
patch from "Inondle", cleaned up and tested
2015-04-20 15:33:03 +00:00
zzz
03ddb1075c BuildHandler: Don't enforce conn limits for P or X 2015-04-20 13:15:30 +00:00
zzz
72eb2c058c Streaming: Move Packet.writeSignedPacket() to PacketLocal 2015-04-20 13:13:55 +00:00
zzz
a100d2ccf9 javadoc, remove unneeded volatile and initializer in TCG 2015-04-20 13:12:21 +00:00
zzz
ecfb3e94c8 javadoc and debug log tweaks for ST2 2015-04-20 13:09:48 +00:00
zzz
c31d6b1ac1 javadoc fix 2015-04-20 13:09:13 +00:00
zzz
65993e1d50 add methods to simplify logging 2015-04-20 13:05:14 +00:00
zzz
47c4c0d6bb add all known dsa-only hosts to list 2015-04-19 19:35:38 +00:00
zzz
b2872e6110 I2CP Multisession - Work in progress:
Start availability notifier in subsession
Availability notifier cleanup
Various log tweaks added while chasing this down
Better subsession state management
I2PSocketManagerFull verifies subsession to force connect()
Successfully tested
2015-04-19 19:05:53 +00:00
zzz
b8c8d5b447 I2CP Multisession - Work in progress:
Accept subclient data message down client's tunnel in IMD
2015-04-19 15:49:02 +00:00
zzz
32049d7bfc I2CP Multisession - Work in progress:
Reuse LS encryption keypair from primary LS
Log tweaks
2015-04-19 14:49:13 +00:00
zzz
f0fdb35ba6 I2CP Multisession - Work in progress:
Fix creating subsession LS from primary LS
2015-04-19 03:35:40 +00:00
zzz
d8baf62966 I2CP Multisession - Work in progress:
Stub out hardcoded list of DSA-only destinations
Tweak client name length in summary bar
Force initial leaseset request for subsession
Send SessionStatus msg before LS request for subsession
2015-04-19 03:11:37 +00:00
zzz
be8f7f9676 I2CP Multisession - Work in progress:
Fix sending CreateSessionMessage for subsession
New AliasedTunnelPool for subsessions, don't reuse TunnelPool,
so it has its own settings
Fix addAlias()
Simplify refreshSettings()
Send status message on subsession create failure
Fix settings for subsession
2015-04-19 01:32:30 +00:00
zzz
57b641bf63 I2CP Multisession - Work in progress:
Fix NPE in receiveMessage()
2015-04-18 20:45:30 +00:00
zzz
ff5d29de1a I2CP Multisession - Work in progress:
Fix NPE in addSubsession() by creating key stream
Set sigtype for subsession
2015-04-18 19:50:14 +00:00
zzz
91e98ba447 I2CP Multisession Work in progress:
Fix NPE in requestLeaseSet()
Fix setting new session ID in SessionStatusMessage
Fix subsession support detection
Streaming: one socket manager, multiple connection managers.
Change data structure for subessions in socket manager
Subsession cleanup on destroy
I2PTunnel: add DSA subsession for non-DSA shared client
Javadocs
2015-04-18 19:01:23 +00:00
zzz
6a644dd0e5 propagate from branch 'i2p.i2p' (head 66743cfb9b4e1c257e4f0a20a318ee7eb1fb607c)
to branch 'i2p.i2p.zzz.multisess' (head 4533ba250cb8e49044f5144b34014e9bc618cdc7)
2015-04-18 14:08:22 +00:00
zzz
7b82393336 atomics and finals 2015-04-17 17:15:22 +00:00
kytv
22993e1ea6 installer/resources/eepsite/jetty-ssl.xml: fix comments 2015-04-17 14:18:56 +00:00
kytv
341bd6d7ca tweak to debian apparmor rules 2015-04-17 14:15:05 +00:00
kytv
13d5a36cfc drop unneeded patch (ty zzz) 2015-04-17 14:14:06 +00:00
str4d
f3bb84f2c0 merge of '4cd641356d3ecf443fa79aa64c8ad553a37022da'
and 'b9d4479f7e0f562a5fd47f2d494fe1b2b0925cbe'
2015-04-17 13:46:44 +00:00
str4d
1d496404be Separate loading and starting of TunnelControllers 2015-04-17 13:45:37 +00:00
zzz
51233371e0 history for prop, -5 2015-04-17 13:43:48 +00:00
zzz
bc0a7ebbbc propagate from branch 'i2p.i2p.zzz.test2' (head b6de226d1664089488ab2b438fe7457e9fb8e563)
to branch 'i2p.i2p' (head 0cf35c87b68a5360bd35257e36dfe7f740e53693)
2015-04-17 13:18:22 +00:00
zzz
72c78b3870 config for SSL to eepsite 2015-04-17 13:03:48 +00:00
zzz
5555c52376 Streaming: Locking for next send time,
rename shadowing field in inner class
2015-04-17 13:00:16 +00:00
str4d
e1842be049 Don't automatically start TCG on Android 2015-04-17 11:21:26 +00:00
zzz
6ceb4fcf42 history for prop, -4 2015-04-16 23:25:49 +00:00
zzz
50b68d4e1c propagate from branch 'i2p.i2p.zzz.815' (head 43bce385eecdf95bba08985211b80099d1224462)
to branch 'i2p.i2p' (head 1b89427bd2952dc4be08fba14ad1d814d722739f)
2015-04-16 23:19:48 +00:00
zzz
3f46228f0b ISJ: Reduce max search depth to reduce ff load
- from 7 to 6 if not ff
- from 7 to 3 if ff (we don't need to backtrack much if any, we know most of the ffs)
2015-04-16 22:02:35 +00:00
zzz
6c954f0b68 Transport: Fix NTCP countPeers()
O/P conn limit adjustment
2015-04-16 21:55:43 +00:00
zzz
69c2ed77a0 recognize Intel model 69 2015-04-16 15:38:13 +00:00
zzz
6f09224bdc sort clients on /configclients 2015-04-16 15:07:08 +00:00
zzz
568c90806d I2CP: Run DistributeLocal jobs inline (ticket #1506) 2015-04-16 14:24:56 +00:00
zzz
6e451c8d4d javadocs 2015-04-16 14:18:10 +00:00
zzz
12fd585625 Transport: Fix active peer count for NTCP,
which will make the network-down message in the console consistent.
Javadocs for getActivePeers() and getActiveSendPeers()
Make getActivePeers() and getActiveSendPeers() abstract in TransportImpl
Make getActivePeers() and getActiveSendPeers() more efficient
Preliminary conn limits for P/X
Log tweaks
2015-04-16 14:13:23 +00:00
zzz
997fbb3392 log on failed plugin update check 2015-04-16 13:14:40 +00:00
zzz
089626f6b1 increase max i2psnark tunnels to 10 2015-04-16 13:13:32 +00:00
zzz
71d2049fe8 OOM log tweak 2015-04-16 13:11:34 +00:00
zzz
e5aee3001f bump -2 2015-04-15 18:20:52 +00:00
dev
ec62bcbf8e propagate from branch 'i2p.i2p.tuna.tmp' (head 73f55ef56c4b4800364bc92d69794a7b6715c5a7)
to branch 'i2p.i2p' (head 20e0a6d51df8fa6918a48ac01c808e56d3540bf1)
2015-04-15 16:25:58 +00:00
dev
a8f013f3e4 merge of '303a05a4ccfb4162f4cca475bca49d77dceb06f9'
and '9c1c14d60b15e3d9eed4b291a7fae39c11d3c993'
2015-04-15 16:17:24 +00:00
dev
037cd78dc7 #1069: Propagate fix into i2p.i2p from i2p.i2p.tuna.tmp
* Replace SimpleScheduler with SimpleTimer2
 * Bump version number
2015-04-15 16:15:53 +00:00
dev
b31ae4bae5 propagate from branch 'i2p.i2p.tuna.tmp' (head 1bba286bdb7f8ba879c4db3f356676151674a201)
to branch 'i2p.i2p' (head 5698b31632398b8156a3b4cc215fed677cf205bf)
2015-04-15 16:08:29 +00:00
dev
54dba980b4 #1069: Replaced SimpleScheduler with SimpleTimer2 in a few places 2015-04-15 15:32:40 +00:00
dev
dc19d2fab3 SimpleTimer2: Removed debug print 2015-04-15 15:18:02 +00:00
dev
3a57310fbe SimpleTimer2: Call the 3-arg addPeridicEvenet() from the 2-arg addPeridicEvenet() 2015-04-15 14:42:39 +00:00
kytv
749e19a1c3 fixes to apparmor profile for i2prouter 2015-04-14 18:50:45 +00:00
zzz
de6608f6b8 Streaming: Handle reset packets without a FROM field, validate
signature using connection's destination
Log tweaks
Remove 0 arg from addRateData() calls
2015-04-14 14:11:48 +00:00
zzz
cd6d9cdd94 Router: Fix NPE on bad share bandwidth config (ticket #1524) 2015-04-14 14:04:31 +00:00
zzz
e45413d417 Update: Don't log an error for the "dummy" updater (ticket #1525) 2015-04-14 14:01:50 +00:00
kytv
11c3230150 updates to apparmor profiles
- hardening (restrict access to proc to owner)
- removing files covered by abstractions
- indentation per apparmor profile style
2015-04-14 01:00:10 +00:00
dev
f5ba1b1b97 #1069: Replaced getInstance() with this 2015-04-09 22:32:59 +00:00
zzz
7825f0f84f i2ptunnel: Remove null workaround and stat, testing passed (ticket #335) 2015-04-09 16:04:06 +00:00
zzz
e5b7e97ff4 Jetty: Set session cookies to HttpOnly in all webapps
i2psnark: Remove extra mime types in i2psnark web.xml;
added to Jetty's default by now, or in our mime.properties file
2015-04-08 19:45:37 +00:00
dev
4613e5f847 #1069: Improved patch according to feedback in ticket 2015-04-08 17:49:28 +00:00
dev
44f8154f07 #1069: Improved patch according to ticket feedback 2015-04-08 17:47:27 +00:00
zzz
5486874d1a Tunnels: Add config to disable Bloom filter for testing 2015-04-08 14:50:12 +00:00
zzz
d868ca4740 Tunnels: Add new Bloom filter size, increase bandwidth limit (ticket #1505) 2015-04-08 14:40:53 +00:00
zzz
780479be4b Tunnel: Add bloom filter warning if high bw but low memory 2015-04-08 13:36:56 +00:00
zzz
4705f01bc5 Router: Move update extraction code to new class in tasks/ 2015-04-08 12:33:16 +00:00
zzz
2f5f91a084 log tweaks 2015-04-08 11:52:02 +00:00
dev
e44fe98c7e propagate from branch 'i2p.i2p' (head 6ae35262874a1828d53ddad22e6a6c4db7b031c1)
to branch 'i2p.i2p.tuna.tmp' (head 7d48c8e1a01f6c6f6cef802e0436c50785d89716)
2015-04-07 17:01:47 +00:00
dev
d8fbc9c170 Formatting 2015-04-06 21:10:49 +00:00
dev
facbe8f9a0 #1069: Deprecated SimpleScheduler and moved functionality into SimpleTimer2 2015-04-06 21:05:24 +00:00
dev
4d8e577ffd findbugs: Added companion equals() and hashCode() methods to existing compareTo() 2015-04-06 16:04:05 +00:00
dev
80eb7635c1 findbugs: Added companion equals() and hashCode() methods to existing compareTo() 2015-04-06 15:40:39 +00:00
dev
e3103762b6 findbugs: Removed synchronization on concurrent object 2015-04-06 15:00:40 +00:00
zzz
6aa1284848 i2ptunnel: Check for total header size too big,
log tweaks
2015-04-04 19:31:20 +00:00
zzz
bb082c35fc recognize more error codes 2015-04-04 19:14:30 +00:00
zzz
f7577e7de8 i2ptunnel: Return specific error pages to client on errors
in HTTP header processing in the HTTP server (ticket #1507)
2015-04-04 19:12:18 +00:00
zzz
b5df13d8b7 propagate from branch 'i2p.i2p' (head 2cb50c2864d750f33039bdbaeb6c15d2bd636ce4)
to branch 'i2p.i2p.zzz.test2' (head 9775e688503ec47dc12efa860a5571317af5f063)
2015-04-04 17:04:52 +00:00
zzz
75a8d8f6d3 more ssl config tweaks 2015-04-03 13:33:59 +00:00
zzz
1ac8d99145 i2ptunnel: Send HTTP server port 443 traffic to the server
transparently, to support HTTPS over the same tunnel,
when so configured.
Jetty: Add extensive help to jetty-ssl.xml for setting
up SSL on the same server.
2015-04-03 12:19:41 +00:00
zzz
485acd6c8d Remove all the startRunning() calls in constructors,
which duplicated the new ones in I2PTunnel, causing all sorts of trouble.
May still need more locking. TBD.
2015-04-02 20:52:40 +00:00
zzz
3ccb03f9be propagate from branch 'i2p.i2p' (head bf7fc6bb213e734788d6527a4a689184ff73d6ad)
to branch 'i2p.i2p.zzz.test2' (head 6a04d890ef0ebf179ec6801d9d96afff26a2e515)
2015-04-01 13:48:18 +00:00
zzz
f3a2af8f10 make job runner quantity configurable 2015-04-01 13:48:06 +00:00
zzz
9dc2ae0d7e fixup after prop 2015-03-28 10:25:45 +00:00
zzz
188bd6db7b propagate from branch 'i2p.i2p' (head 2ce39645bf3b3b7fc2f083ebcb073f104114e939)
to branch 'i2p.i2p.zzz.815' (head 4f0279eb4cf13e547a64913443ff7819a43962c0)
2015-03-27 14:47:49 +00:00
zzz
3a8ce64c84 I2PTunnel client-side locking fixes (ticket #815)
Checkin of patches from Oct. 2013, based on 0.9.8.1.
Had some issues back then, and not tested recently.
Prop from i2p.i2p to follow.
2015-03-27 14:16:41 +00:00
zzz
1293dccf35 I2CP Multisession support and multiple destinations in one tunnel pool.
Work in progress.
Router-side I2CP mostly done.
Client-side I2CP mostly done but undecided on how to handle
listeners.
Streaming stubbed out but may be wrong, may need multiple socket managers,
not clear how to proceed.
I2PTunnel not started.
Blacklist of DSA-only dests not started.
Router leaseset publishing not correct. Not clear whether to have
additional tunnel pools with flags, or put the tunnel pools into
the client hashmap twice. Client config contains destination,
may need to move that to tunnel pool.
2015-03-18 12:59:50 +00:00
678 changed files with 64394 additions and 47524 deletions

View File

@@ -33,7 +33,8 @@ trans.de = apps/i2ptunnel/locale-proxy/messages_de.po
trans.es = apps/i2ptunnel/locale-proxy/messages_es.po
trans.fr = apps/i2ptunnel/locale-proxy/messages_fr.po
trans.hu = apps/i2ptunnel/locale-proxy/messages_hu.po
trans.id = apps/i2ptunnel/locale-proxy/messages_id.po
;; Java converts id to in
trans.id = apps/i2ptunnel/locale-proxy/messages_in.po
trans.it = apps/i2ptunnel/locale-proxy/messages_it.po
trans.nb = apps/i2ptunnel/locale-proxy/messages_nb.po
trans.nl = apps/i2ptunnel/locale-proxy/messages_nl.po
@@ -85,7 +86,8 @@ trans.es = apps/routerconsole/locale-news/messages_es.po
trans.fi = apps/routerconsole/locale-news/messages_fi.po
trans.fr = apps/routerconsole/locale-news/messages_fr.po
trans.he = apps/routerconsole/locale-news/messages_he.po
trans.id = apps/routerconsole/locale-news/messages_id.po
;; Java converts id to in
trans.id = apps/routerconsole/locale-news/messages_in.po
trans.it = apps/routerconsole/locale-news/messages_it.po
trans.ja = apps/routerconsole/locale-news/messages_ja.po
trans.ko = apps/routerconsole/locale-news/messages_ko.po
@@ -217,7 +219,8 @@ trans.es = apps/susimail/locale/messages_es.po
trans.fi = apps/susimail/locale/messages_fi.po
trans.fr = apps/susimail/locale/messages_fr.po
trans.hu = apps/susimail/locale/messages_hu.po
trans.id = apps/susimail/locale/messages_id.po
;; Java converts id to in
trans.id = apps/susimail/locale/messages_in.po
trans.it = apps/susimail/locale/messages_it.po
trans.ja = apps/susimail/locale/messages_ja.po
trans.mg = apps/susimail/locale/messages_mg.po
@@ -267,6 +270,8 @@ source_lang = en
;;trans.ca = installer/resources/locale/po/messages_ca.po
trans.de = installer/resources/locale/po/messages_de.po
trans.es = installer/resources/locale/po/messages_es.po
;; currently fails check
;;trans.fi = installer/resources/locale/po/messages_fi.po
trans.fr = installer/resources/locale/po/messages_fr.po
trans.id = installer/resources/locale/po/messages_id.po
trans.it = installer/resources/locale/po/messages_it.po
@@ -294,9 +299,11 @@ type = PROPERTIES
trans.cs = core/java/src/gnu/getopt/MessagesBundle_cs.properties
trans.de = core/java/src/gnu/getopt/MessagesBundle_de.properties
trans.es = core/java/src/gnu/getopt/MessagesBundle_es.properties
trans.fi = core/java/src/gnu/getopt/MessagesBundle_fi.properties
trans.fr = core/java/src/gnu/getopt/MessagesBundle_fr.properties
trans.hu = core/java/src/gnu/getopt/MessagesBundle_hu.properties
trans.id = core/java/src/gnu/getopt/MessagesBundle_id.properties
;; Java converts id to in
trans.id = core/java/src/gnu/getopt/MessagesBundle_in.properties
trans.it = core/java/src/gnu/getopt/MessagesBundle_it.properties
trans.ja = core/java/src/gnu/getopt/MessagesBundle_ja.properties
trans.ko = core/java/src/gnu/getopt/MessagesBundle_ko.properties
@@ -318,15 +325,18 @@ trans.zh_CN = core/java/src/gnu/getopt/MessagesBundle_zh.properties
[I2P.streaming]
source_file = apps/ministreaming/locale/messages_en.po
source_lang = en
trans.ca = apps/ministreaming/locale/messages_ca.po
trans.de = apps/ministreaming/locale/messages_de.po
trans.es = apps/ministreaming/locale/messages_es.po
trans.fr = apps/ministreaming/locale/messages_fr.po
trans.id = apps/ministreaming/locale/messages_id.po
;; Java converts id to in
trans.id = apps/ministreaming/locale/messages_in.po
trans.it = apps/ministreaming/locale/messages_it.po
trans.nb = apps/ministreaming/locale/messages_nb.po
trans.pl = apps/ministreaming/locale/messages_pl.po
trans.ro = apps/ministreaming/locale/messages_ro.po
trans.ru_RU = apps/ministreaming/locale/messages_ru.po
trans.sv_SE = apps/ministreaming/locale/messages_sv.po
trans.uk_UA = apps/ministreaming/locale/messages_uk.po
trans.zh_CN = apps/ministreaming/locale/messages_zh.po

View File

@@ -80,6 +80,10 @@ Public domain except as listed below:
Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
See licenses/LICENSE-LGPLv2.1.txt
HostnameVerifier:
From Apache HttpClient 4.4.1 and HttpCore 4.4.1
See licenses/LICENSE-Apache2.0.txt
Router (router.jar):
Public domain except as listed below:
@@ -87,7 +91,7 @@ Public domain except as listed below:
From freenet
See licenses/LICENSE-GPLv2.txt
UPnP subsystem (CyberLink) 2.1:
UPnP subsystem (CyberLink) 3.0:
Copyright (C) 2003-2010 Satoshi Konno
See licenses/LICENSE-UPnP.txt
@@ -182,7 +186,7 @@ Applications:
By welterde.
See licenses/LICENSE-GPLv2.txt
Jetty 8.1.16.v20140903:
Jetty 8.1.17.v20150415:
See licenses/ABOUT-Jetty.html
See licenses/NOTICE-Jetty.html
See licenses/LICENSE-Apache2.0.txt
@@ -248,8 +252,8 @@ Applications:
Bundles systray4j-2.4.1:
See licenses/LICENSE-LGPLv2.1.txt
Tomcat 6.0.43:
Copyright 1999-2014 The Apache Software Foundation
Tomcat 6.0.44:
Copyright 1999-2015 The Apache Software Foundation
See licenses/LICENSE-Apache2.0.txt
See licenses/NOTICE-Tomcat.txt

View File

@@ -38,7 +38,6 @@ import net.i2p.I2PAppContext;
import net.i2p.app.*;
import net.i2p.client.I2PClient;
import net.i2p.util.I2PAppThread;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer2;
/**
@@ -214,9 +213,7 @@ public class BOB implements Runnable, ClientApp {
// 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.
SimpleScheduler Y1 = SimpleScheduler.getInstance();
SimpleTimer2 Y2 = SimpleTimer2.getInstance();
i = Y1.hashCode();
i = Y2.hashCode();
{
File cfg = new File(configLocation);

View File

@@ -30,16 +30,15 @@ import net.i2p.client.streaming.I2PSocketManager;
*/
public class I2Plistener implements Runnable {
private NamedDB info, database;
private Logger _log;
public I2PSocketManager socketManager;
public I2PServerSocket serverSocket;
private AtomicBoolean lives;
private final NamedDB info, database;
private final Logger _log;
private final I2PServerSocket serverSocket;
private final AtomicBoolean lives;
/**
* Constructor
* @param SS
* @param S
* @param S unused
* @param info
* @param database
* @param _log
@@ -48,7 +47,6 @@ public class I2Plistener implements Runnable {
this.database = database;
this.info = info;
this._log = _log;
this.socketManager = S;
this.serverSocket = SS;
this.lives = lives;
}

View File

@@ -15,7 +15,6 @@
*/
package net.i2p.BOB;
import net.i2p.util.SimpleScheduler;
import net.i2p.util.SimpleTimer2;
/**
@@ -31,12 +30,10 @@ public class Main {
*/
public static void main(String[] args) {
// THINK THINK THINK THINK THINK THINK
SimpleScheduler Y1 = SimpleScheduler.getInstance();
SimpleTimer2 Y2 = SimpleTimer2.getInstance();
BOB.main(args);
Y2.stop();
Y1.stop();
}
}

View File

@@ -64,7 +64,7 @@ public class NamedDB {
}
/**
* Find objects in the array, returns it's index or throws exception
* Find objects in the array, returns its index or throws exception
* @param key
* @return an objects index
* @throws ArrayIndexOutOfBoundsException when key does not exist

View File

@@ -30,12 +30,11 @@ import net.i2p.client.streaming.I2PSocketManager;
*/
public class TCPlistener implements Runnable {
private NamedDB info, database;
private Logger _log;
public I2PSocketManager socketManager;
public I2PServerSocket serverSocket;
private ServerSocket listener;
private AtomicBoolean lives;
private final NamedDB info, database;
private final Logger _log;
private final I2PSocketManager socketManager;
private final ServerSocket listener;
private final AtomicBoolean lives;
/**
* Constructor

View File

@@ -34,15 +34,17 @@ import net.i2p.util.Log;
* The skeletal frame is here, just needs to be finished.
*
* @author sponge
* @deprecated incomplete, unused
*/
public class UDPIOthread implements I2PSessionListener, Runnable {
private NamedDB info;
private Log _log;
private Socket socket;
private final NamedDB info;
private final Log _log;
private final Socket socket;
private DataInputStream in;
private DataOutputStream out;
private I2PSession _session;
private final I2PSession _session;
// FIXME never set
private Destination _peerDestination;
private boolean up;
@@ -58,7 +60,6 @@ public class UDPIOthread implements I2PSessionListener, Runnable {
this._log = _log;
this.socket = socket;
this._session = _session;
}
/**

View File

@@ -159,8 +159,13 @@ class AddressBook {
* @since 0.8.7
*/
public Iterator<Map.Entry<String, String>> iterator() {
if (this.subFile != null)
return new ConfigIterator(this.subFile);
if (this.subFile != null) {
try {
return new ConfigIterator(this.subFile);
} catch (IOException ioe) {
return new ConfigIterator();
}
}
return this.addresses.entrySet().iterator();
}

View File

@@ -22,6 +22,7 @@
package net.i2p.addressbook;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -41,7 +42,7 @@ import java.util.NoSuchElementException;
*
* @since 0.8.7
*/
class ConfigIterator implements Iterator<Map.Entry<String, String>> {
class ConfigIterator implements Iterator<Map.Entry<String, String>>, Closeable {
private BufferedReader input;
private ConfigEntry next;
@@ -54,11 +55,9 @@ class ConfigIterator implements Iterator<Map.Entry<String, String>> {
/**
* An iterator over the key/value pairs in the file.
*/
public ConfigIterator(File file) {
try {
public ConfigIterator(File file) throws IOException {
FileInputStream fileStream = new FileInputStream(file);
input = new BufferedReader(new InputStreamReader(fileStream));
} catch (IOException ioe) {}
input = new BufferedReader(new InputStreamReader(fileStream, "UTF-8"));
}
public boolean hasNext() {

View File

@@ -116,7 +116,7 @@ class ConfigParser {
public static Map<String, String> parse(File file) throws IOException {
FileInputStream fileStream = new FileInputStream(file);
BufferedReader input = new BufferedReader(new InputStreamReader(
fileStream));
fileStream, "UTF-8"));
Map<String, String> rv = parse(input);
try {
fileStream.close();
@@ -205,7 +205,7 @@ class ConfigParser {
public static List<String> parseSubscriptions(File file) throws IOException {
FileInputStream fileStream = new FileInputStream(file);
BufferedReader input = new BufferedReader(new InputStreamReader(
fileStream));
fileStream, "UTF-8"));
List<String> rv = parseSubscriptions(input);
try {
fileStream.close();

View File

@@ -23,8 +23,9 @@ package net.i2p.addressbook;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Date;
/**
@@ -56,8 +57,8 @@ class Log {
public void append(String entry) {
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(this.file,
true));
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(this.file,
true), "UTF-8"));
String timestamp = new Date().toString();
bw.write(timestamp + " -- " + entry);
bw.newLine();

View File

@@ -26,6 +26,7 @@ import java.util.Iterator;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.util.PortMapper;
/**
* An iterator over the subscriptions in a SubscriptionList. Note that this iterator
@@ -69,11 +70,13 @@ class SubscriptionIterator implements Iterator<AddressBook> {
* Yes, the EepGet fetch() is done in here in next().
*
* see java.util.Iterator#next()
* @return an AddressBook (empty if the minimum delay has not been met)
* @return non-null AddressBook (empty if the minimum delay has not been met,
* or there is no proxy tunnel, or the fetch otherwise fails)
*/
public AddressBook next() {
Subscription sub = this.subIterator.next();
if (sub.getLastFetched() + this.delay < I2PAppContext.getGlobalContext().clock().now()) {
if (sub.getLastFetched() + this.delay < I2PAppContext.getGlobalContext().clock().now() &&
I2PAppContext.getGlobalContext().portMapper().getPort(PortMapper.SVC_HTTP_PROXY) >= 0) {
//System.err.println("Fetching addressbook from " + sub.getLocation());
return new AddressBook(sub, this.proxyHost, this.proxyPort);
} else {

View File

@@ -28,4 +28,11 @@
<url-pattern>/*</url-pattern>
</servlet-mapping>
<!-- this webapp doesn't actually use sessions or cookies -->
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<http-only>true</http-only>
</cookie-config>
</session-config>
</web-app>

View File

@@ -1,4 +1,4 @@
# Last Modified: Mon, 16 Feb 2015
# Last Modified: Sun Apr 12 22:08:32 2015
# vim:syntax=apparmor et ts=8 sw=4
#include <tunables/global>
@@ -18,20 +18,20 @@ $INSTALL_PATH/{i2prouter,runplain.sh} flags=(complain) {
owner $INSTALL_PATH/** rwklm,
# Needed for Java
@{PROC} r,
@{PROC}/[0-9]*/net/if_inet6 r,
@{PROC}/[0-9]*/net/ipv6_route r,
@{PROC}/[0-9]*/status r,
@{PROC}/[0-9]*/stat r,
@{PROC}/[0-9]*/cmdline r,
@{PROC}/1/comm r,
owner @{PROC} r,
owner @{PROC}/[0-9]*/ r,
owner @{PROC}/[0-9]*/status r,
owner @{PROC}/[0-9]*/stat r,
owner @{PROC}/[0-9]*/cmdline r,
@{PROC}/uptime r,
@{PROC}/sys/kernel/pid_max r,
/sys/devices/system/cpu/ r,
/sys/devices/system/cpu/** r,
/dev/random r,
/dev/urandom r,
@{PROC}/1/comm r,
/etc/ssl/certs/java/** r,
/etc/timezone r,
@@ -51,16 +51,7 @@ $INSTALL_PATH/{i2prouter,runplain.sh} flags=(complain) {
# Fonts are needed for I2P's graphs
/etc/fonts/** r,
/usr/share/fontconfig/ r,
/usr/share/fontconfig/** r,
/usr/share/fonts/ r,
/usr/share/fonts/** r,
/usr/share/fonts/truetype/ r,
/usr/share/fonts/truetype/** r,
/usr/share/java/java-atk-wrapper.jar r,
/var/cache/fontconfig/ r,
/var/cache/fontconfig/** r,
# Used by some plugins
/usr/share/java/eclipse-ecj-*.jar r,

View File

@@ -26,7 +26,7 @@ then
fi
# on windows, one must specify the path of commnad find
# since windows has its own retarded version of find.
# since windows has its own version of find.
if which find|grep -q -i windows ; then
export PATH=.:/bin:/usr/local/bin:$PATH
fi

View File

@@ -4,7 +4,7 @@
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# Denis Blank <gribua@gmail.com>, 2011
# Denis Lysenko <gribua@gmail.com>, 2011
# LinuxChata, 2014
# madjong <madjong@i2pmail.org>, 2014
msgid ""
@@ -12,9 +12,9 @@ msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-01-09 19:27+0000\n"
"PO-Revision-Date: 2014-12-17 17:00+0000\n"
"Last-Translator: madjong <madjong@i2pmail.org>\n"
"Language-Team: Ukrainian (Ukraine) (http://www.transifex.com/projects/p/I2P/language/uk_UA/)\n"
"PO-Revision-Date: 2015-08-07 16:31+0000\n"
"Last-Translator: Denis Lysenko <gribua@gmail.com>\n"
"Language-Team: Ukrainian (Ukraine) (http://www.transifex.com/otf/I2P/language/uk_UA/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@@ -25,7 +25,7 @@ then
fi
# on windows, one must specify the path of commnad find
# since windows has its own retarded version of find.
# since windows has its own version of find.
if which find|grep -q -i windows ; then
export PATH=.:/bin:/usr/local/bin:$PATH
fi

View File

@@ -20,6 +20,8 @@
package org.klomp.snark;
import java.util.Arrays;
/**
* Container of a byte array representing set and unset bits.
@@ -66,7 +68,7 @@ public class BitField
/**
* This returns the actual byte array used. Changes to this array
* effect this BitField. Note that some bits at the end of the byte
* affect this BitField. Note that some bits at the end of the byte
* array are supposed to be always unset if they represent bits
* bigger then the size of the bitfield.
*/
@@ -105,6 +107,37 @@ public class BitField
}
}
/**
* Sets the given bit to false.
*
* @exception IndexOutOfBoundsException if bit is smaller then zero
* bigger then size (inclusive).
* @since 0.9.22
*/
public void clear(int bit)
{
if (bit < 0 || bit >= size)
throw new IndexOutOfBoundsException(Integer.toString(bit));
int index = bit/8;
int mask = 128 >> (bit % 8);
synchronized(this) {
if ((bitfield[index] & mask) != 0) {
count--;
bitfield[index] &= ~mask;
}
}
}
/**
* Sets all bits to true.
*
* @since 0.9.21
*/
public void setAll() {
Arrays.fill(bitfield, (byte) 0xff);
count = size;
}
/**
* Return true if the bit is set or false if it is not.
*

View File

@@ -90,17 +90,20 @@ abstract class ExtensionHandler {
peer.setHandshakeMap(map);
Map<String, BEValue> msgmap = map.get("m").getMap();
if (msgmap.get(TYPE_PEX) != null) {
if (log.shouldLog(Log.DEBUG))
log.debug("Peer supports PEX extension: " + peer);
// peer state calls peer listener calls sendPEX()
}
if (log.shouldLog(Log.DEBUG))
log.debug("Peer " + peer + " supports extensions: " + msgmap.keySet());
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()
}
//if (msgmap.get(TYPE_PEX) != null) {
// 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();
@@ -204,30 +207,31 @@ abstract class ExtensionHandler {
if (log.shouldLog(Log.DEBUG))
log.debug("Got request for " + piece + " from: " + peer);
byte[] pc;
int totalSize;
synchronized(state) {
pc = state.getChunk(piece);
totalSize = state.getSize();
}
sendPiece(peer, piece, pc);
sendPiece(peer, piece, pc, totalSize);
// Do this here because PeerConnectionOut only reports for PIECE messages
peer.uploaded(pc.length);
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);
// On close reading of BEP 9, this is the total metadata size.
// Prior to 0.9.21, we sent the piece size, so we can't count on it.
// just ignore it. The actual length will be verified in saveChunk()
//int size = map.get("total_size").getInt();
//if (log.shouldLog(Log.DEBUG))
// log.debug("Got data for " + piece + " length " + size + " from: " + peer);
boolean done;
int chk = -1;
synchronized(state) {
if (state.isComplete())
return;
int len = is.available();
if (len != size) {
// probably fatal
if (log.shouldLog(Log.WARN))
log.warn("total_size " + size + " but avail data " + len);
}
peer.downloaded(len);
listener.downloaded(peer, len);
// this checks the size
done = state.saveChunk(piece, bs, bs.length - len, len);
if (log.shouldLog(Log.INFO))
log.info("Got chunk " + piece + " from " + peer);
@@ -290,11 +294,15 @@ abstract class ExtensionHandler {
}
}
private static void sendPiece(Peer peer, int piece, byte[] data) {
private static void sendPiece(Peer peer, int piece, byte[] data, int totalSize) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("msg_type", Integer.valueOf(TYPE_DATA));
map.put("piece", Integer.valueOf(piece));
map.put("total_size", Integer.valueOf(data.length));
// BEP 9
// "This key has the same semantics as the 'metadata_size' in the extension header"
// which apparently means the same value. Fixed in 0.9.21.
//map.put("total_size", Integer.valueOf(data.length));
map.put("total_size", Integer.valueOf(totalSize));
byte[] dict = BEncoder.bencode(map);
byte[] payload = new byte[dict.length + data.length];
System.arraycopy(dict, 0, payload, 0, dict.length);

View File

@@ -14,6 +14,7 @@ import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.I2PClient;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.streaming.I2PServerSocket;
@@ -255,6 +256,8 @@ public class I2PSnarkUtil {
opts.setProperty("i2p.streaming.disableRejectLogging", "true");
if (opts.getProperty("i2p.streaming.answerPings") == null)
opts.setProperty("i2p.streaming.answerPings", "false");
if (opts.getProperty(I2PClient.PROP_SIGTYPE) == null)
opts.setProperty(I2PClient.PROP_SIGTYPE, "EdDSA_SHA512_Ed25519");
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
_connecting = false;
}
@@ -328,7 +331,7 @@ public class I2PSnarkUtil {
return rv;
} catch (I2PException ie) {
_banlist.add(dest);
_context.simpleScheduler().addEvent(new Unbanlist(dest), 10*60*1000);
_context.simpleTimer2().addEvent(new Unbanlist(dest), 10*60*1000);
IOException ioe = new IOException("Unable to reach the peer " + peer);
ioe.initCause(ie);
throw ioe;
@@ -456,7 +459,7 @@ public class I2PSnarkUtil {
return null;
}
String getOurIPString() {
public String getOurIPString() {
Destination dest = getMyDestination();
if (dest != null)
return dest.toBase64();

View File

@@ -55,11 +55,13 @@ class Message
byte type;
// Used for HAVE, REQUEST, PIECE and CANCEL messages.
// Also SUGGEST, REJECT, ALLOWED_FAST
// low byte used for EXTENSION message
// low two bytes used for PORT message
int piece;
// Used for REQUEST, PIECE and CANCEL messages.
// Also REJECT
int begin;
int length;
@@ -104,15 +106,18 @@ class Message
int datalen = 1;
// piece is 4 bytes.
if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL)
if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL ||
type == SUGGEST || type == REJECT || type == ALLOWED_FAST)
datalen += 4;
// begin/offset is 4 bytes
if (type == REQUEST || type == PIECE || type == CANCEL)
if (type == REQUEST || type == PIECE || type == CANCEL ||
type == REJECT)
datalen += 4;
// length is 4 bytes
if (type == REQUEST || type == CANCEL)
if (type == REQUEST || type == CANCEL ||
type == REJECT)
datalen += 4;
// msg type is 1 byte
@@ -131,15 +136,18 @@ class Message
dos.writeByte(type & 0xFF);
// Send additional info (piece number)
if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL)
if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL ||
type == SUGGEST || type == REJECT || type == ALLOWED_FAST)
dos.writeInt(piece);
// Send additional info (begin/offset)
if (type == REQUEST || type == PIECE || type == CANCEL)
if (type == REQUEST || type == PIECE || type == CANCEL ||
type == REJECT)
dos.writeInt(begin);
// Send additional info (length); for PIECE this is implicit.
if (type == REQUEST || type == CANCEL)
if (type == REQUEST || type == CANCEL ||
type == REJECT)
dos.writeInt(length);
if (type == EXTENSION)
@@ -173,21 +181,32 @@ class Message
case UNINTERESTED:
return "UNINTERESTED";
case HAVE:
return "HAVE(" + piece + ")";
return "HAVE(" + piece + ')';
case BITFIELD:
return "BITFIELD";
case REQUEST:
return "REQUEST(" + piece + "," + begin + "," + length + ")";
return "REQUEST(" + piece + ',' + begin + ',' + length + ')';
case PIECE:
return "PIECE(" + piece + "," + begin + "," + length + ")";
return "PIECE(" + piece + ',' + begin + ',' + length + ')';
case CANCEL:
return "CANCEL(" + piece + "," + begin + "," + length + ")";
return "CANCEL(" + piece + ',' + begin + ',' + length + ')';
case PORT:
return "PORT(" + piece + ")";
return "PORT(" + piece + ')';
case EXTENSION:
return "EXTENSION(" + piece + ',' + data.length + ')';
// fast extensions below here
case SUGGEST:
return "SUGGEST(" + piece + ')';
case HAVE_ALL:
return "HAVE_ALL";
case HAVE_NONE:
return "HAVE_NONE";
case REJECT:
return "REJECT(" + piece + ',' + begin + ',' + length + ')';
case ALLOWED_FAST:
return "ALLOWED_FAST(" + piece + ')';
default:
return "<UNKNOWN>";
return "UNKNOWN (" + type + ')';
}
}
}

View File

@@ -108,7 +108,8 @@ class PartialPiece implements Comparable<PartialPiece> {
/**
* Convert this PartialPiece to a request for the next chunk.
* Used by PeerState only.
* Used by PeerState only. This depends on the downloaded value
* as set by setDownloaded() or read().
*/
public Request getRequest() {
@@ -128,14 +129,16 @@ class PartialPiece implements Comparable<PartialPiece> {
}
/**
* How many bytes are good - only valid by setDownloaded()
* How many bytes are good - as set by setDownloaded() or read()
*/
public int getDownloaded() {
return this.off;
}
/**
* Call this before returning a PartialPiece to the PeerCoordinator
* Call this if necessary before returning a PartialPiece to the PeerCoordinator.
* We do not use a bitmap to track individual chunks received.
* Any chunks after a 'hole' will be lost.
* @since 0.9.1
*/
public void setDownloaded(int offset) {
@@ -191,11 +194,20 @@ class PartialPiece implements Comparable<PartialPiece> {
/**
* Blocking.
* If offset matches the previous downloaded amount
* (as set by a previous call to read() or setDownlaoded()),
* the downloaded amount will be incremented by len.
*
* @since 0.9.1
*/
public void read(DataInputStream din, int off, int len) throws IOException {
public void read(DataInputStream din, int offset, int len) throws IOException {
if (bs != null) {
din.readFully(bs, off, len);
din.readFully(bs, offset, len);
synchronized (this) {
// only works for in-order chunks
if (this.off == offset)
this.off += len;
}
} else {
// read in fully before synching on raf
ByteArray ba;
@@ -211,8 +223,11 @@ class PartialPiece implements Comparable<PartialPiece> {
synchronized (this) {
if (raf == null)
createTemp();
raf.seek(off);
raf.seek(offset);
raf.write(tmp);
// only works for in-order chunks
if (this.off == offset)
this.off += len;
}
if (ba != null)
_cache.release(ba, false);

View File

@@ -79,15 +79,15 @@ public class Peer implements Comparable<Peer>
private long uploaded_old[] = {-1,-1,-1};
private long downloaded_old[] = {-1,-1,-1};
// bytes per bt spec: 0011223344556677
static final long OPTION_EXTENSION = 0x0000000000100000l;
static final long OPTION_FAST = 0x0000000000000004l;
static final long OPTION_DHT = 0x0000000000000001l;
// bytes per bt spec: 0011223344556677
private static final long OPTION_EXTENSION = 0x0000000000100000l;
private static final long OPTION_FAST = 0x0000000000000004l;
//private 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 static final long OPTION_AZMP = 0x1000000000000000l;
private long options;
/**
@@ -297,7 +297,7 @@ public class Peer implements Comparable<Peer>
if (_log.shouldLog(Log.DEBUG))
_log.debug("Start running the reader with " + toString());
// Use this thread for running the incomming connection.
// Use this thread for running the incoming connection.
// The outgoing connection creates its own Thread.
out.startup();
Thread.currentThread().setName("Snark reader from " + peerID);
@@ -338,6 +338,9 @@ public class Peer implements Comparable<Peer>
dout.write("BitTorrent protocol".getBytes("UTF-8"));
// Handshake write - options
long myOptions = OPTION_EXTENSION;
// we can't handle HAVE_ALL or HAVE_NONE if we don't know the number of pieces
if (metainfo != null)
myOptions |= OPTION_FAST;
// FIXME get util here somehow
//if (util.getDHT() != null)
// myOptions |= OPTION_I2P_DHT;
@@ -385,15 +388,15 @@ public class Peer implements Comparable<Peer>
if (options != 0) {
// send them something in runConnection() above
if (_log.shouldLog(Log.DEBUG))
_log.debug("Peer supports options 0x" + Long.toString(options, 16) + ": " + toString());
_log.debug("Peer supports options 0x" + Long.toHexString(options) + ": " + toString());
}
return bs;
}
/** @since 0.8.4 */
public long getOptions() {
return options;
/** @since 0.9.21 */
public boolean supportsFast() {
return (options & OPTION_FAST) != 0;
}
/** @since 0.8.4 */

View File

@@ -98,44 +98,48 @@ class PeerConnectionIn implements Runnable
}
byte b = din.readByte();
Message m = new Message();
m.type = b;
switch (b)
{
case 0:
case Message.CHOKE:
ps.chokeMessage(true);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received choke from " + peer);
break;
case 1:
case Message.UNCHOKE:
ps.chokeMessage(false);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received unchoke from " + peer);
break;
case 2:
case Message.INTERESTED:
ps.interestedMessage(true);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received interested from " + peer);
break;
case 3:
case Message.UNINTERESTED:
ps.interestedMessage(false);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received not interested from " + peer);
break;
case 4:
case Message.HAVE:
piece = din.readInt();
ps.haveMessage(piece);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received havePiece(" + piece + ") from " + peer);
break;
case 5:
case Message.BITFIELD:
byte[] bitmap = new byte[i-1];
din.readFully(bitmap);
ps.bitfieldMessage(bitmap);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received bitmap from " + peer + ": size=" + (i-1) /* + ": " + ps.bitfield */ );
break;
case 6:
case Message.REQUEST:
piece = din.readInt();
begin = din.readInt();
len = din.readInt();
@@ -143,7 +147,8 @@ class PeerConnectionIn implements Runnable
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received request(" + piece + "," + begin + ") from " + peer);
break;
case 7:
case Message.PIECE:
piece = din.readInt();
begin = din.readInt();
len = i-9;
@@ -165,7 +170,8 @@ class PeerConnectionIn implements Runnable
_log.debug("Received UNWANTED data(" + piece + "," + begin + ") from " + peer);
}
break;
case 8:
case Message.CANCEL:
piece = din.readInt();
begin = din.readInt();
len = din.readInt();
@@ -173,13 +179,15 @@ class PeerConnectionIn implements Runnable
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received cancel(" + piece + "," + begin + ") from " + peer);
break;
case 9: // PORT message
case Message.PORT:
int port = din.readUnsignedShort();
ps.portMessage(port);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received port message from " + peer);
break;
case 20: // Extension message
case Message.EXTENSION:
int id = din.readUnsignedByte();
byte[] payload = new byte[i-2];
din.readFully(payload);
@@ -187,6 +195,43 @@ class PeerConnectionIn implements Runnable
_log.debug("Received extension message from " + peer);
ps.extensionMessage(id, payload);
break;
// fast extensions below here
case Message.SUGGEST:
piece = din.readInt();
ps.suggestMessage(piece);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received suggest(" + piece + ") from " + peer);
break;
case Message.HAVE_ALL:
ps.haveMessage(true);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received have_all from " + peer);
break;
case Message.HAVE_NONE:
ps.haveMessage(false);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received have_none from " + peer);
break;
case Message.REJECT:
piece = din.readInt();
begin = din.readInt();
len = din.readInt();
ps.rejectMessage(piece, begin, len);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received reject(" + piece + ',' + begin + ',' + len + ") from " + peer);
break;
case Message.ALLOWED_FAST:
piece = din.readInt();
ps.allowedFastMessage(piece);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Received allowed_fast(" + piece + ") from " + peer);
break;
default:
byte[] bs = new byte[i-1];
din.readFully(bs);

View File

@@ -22,15 +22,15 @@ package org.klomp.snark;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;
import net.i2p.I2PAppContext;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
//import net.i2p.util.SimpleScheduler;
//import net.i2p.util.SimpleTimer;
class PeerConnectionOut implements Runnable
@@ -43,7 +43,7 @@ class PeerConnectionOut implements Runnable
private boolean quit;
// Contains Messages.
private final List<Message> sendQueue = new ArrayList<Message>();
private final BlockingQueue<Message> sendQueue = new LinkedBlockingQueue<Message>();
private static final AtomicLong __id = new AtomicLong();
private final long _id;
@@ -125,6 +125,16 @@ class PeerConnectionOut implements Runnable
if (state.choking) {
it.remove();
//SimpleTimer.getInstance().removeEvent(nm.expireEvent);
if (peer.supportsFast()) {
Message r = new Message();
r.type = Message.REJECT;
r.piece = nm.piece;
r.begin = nm.begin;
r.length = nm.length;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Send " + peer + ": " + r);
r.sendMessage(dout);
}
}
nm = null;
}
@@ -142,8 +152,8 @@ class PeerConnectionOut implements Runnable
it.remove();
}
}
if (m == null && !sendQueue.isEmpty()) {
m = sendQueue.remove(0);
if (m == null) {
m = sendQueue.poll();
//SimpleTimer.getInstance().removeEvent(m.expireEvent);
}
}
@@ -160,6 +170,8 @@ class PeerConnectionOut implements Runnable
lastSent = System.currentTimeMillis();
// Remove all piece messages after sending a choke message.
// FiXME this causes REJECT messages to be sent before sending the CHOKE;
// BEP 6 recommends sending them after.
if (m.type == Message.CHOKE)
removeMessage(Message.PIECE);
@@ -234,7 +246,7 @@ class PeerConnectionOut implements Runnable
{
synchronized(sendQueue)
{
sendQueue.add(m);
sendQueue.offer(m);
sendQueue.notifyAll();
}
}
@@ -278,11 +290,22 @@ class PeerConnectionOut implements Runnable
while (it.hasNext())
{
Message m = it.next();
if (m.type == type)
{
if (m.type == type) {
it.remove();
removed = true;
}
if (type == Message.PIECE && peer.supportsFast()) {
Message r = new Message();
r.type = Message.REJECT;
r.piece = m.piece;
r.begin = m.begin;
r.length = m.length;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Send " + peer + ": " + r);
try {
r.sendMessage(dout);
} catch (IOException ioe) {}
}
}
}
sendQueue.notifyAll();
}
@@ -297,7 +320,7 @@ class PeerConnectionOut implements Runnable
synchronized(sendQueue)
{
if(sendQueue.isEmpty())
sendQueue.add(m);
sendQueue.offer(m);
sendQueue.notifyAll();
}
}
@@ -350,12 +373,19 @@ class PeerConnectionOut implements Runnable
void sendBitfield(BitField bitfield)
{
Message m = new Message();
m.type = Message.BITFIELD;
m.data = bitfield.getFieldBytes();
m.off = 0;
m.len = m.data.length;
addMessage(m);
boolean fast = peer.supportsFast();
if (fast && bitfield.complete()) {
sendHaveAll();
} else if (fast && bitfield.count() <= 0) {
sendHaveNone();
} else {
Message m = new Message();
m.type = Message.BITFIELD;
m.data = bitfield.getFieldBytes();
m.off = 0;
m.len = m.data.length;
addMessage(m);
}
}
/** reransmit requests not received in 7m */
@@ -480,7 +510,6 @@ class PeerConnectionOut implements Runnable
m.len = length;
// since we have the data already loaded, queue a timeout to remove it
// no longer prefetched
//SimpleScheduler.getInstance().addEvent(new RemoveTooSlow(m), SEND_TIMEOUT);
addMessage(m);
}
@@ -511,7 +540,8 @@ class PeerConnectionOut implements Runnable
}
/**
* Remove all Request messages from the queue
* Remove all Request messages from the queue.
* Does not send a cancel message.
* @since 0.8.2
*/
void cancelRequestMessages() {
@@ -523,9 +553,12 @@ class PeerConnectionOut implements Runnable
}
}
// Called by the PeerState when the other side doesn't want this
// request to be handled anymore. Removes any pending Piece Message
// from out send queue.
/**
* Called by the PeerState when the other side doesn't want this
* request to be handled anymore. Removes any pending Piece Message
* from out send queue.
* Does not send a cancel message.
*/
void cancelRequest(int piece, int begin, int length)
{
synchronized (sendQueue)
@@ -561,4 +594,50 @@ class PeerConnectionOut implements Runnable
m.piece = port;
addMessage(m);
}
/**
* Unused
* @since 0.9.21
*/
void sendSuggest(int piece) {
Message m = new Message();
m.type = Message.SUGGEST;
m.piece = piece;
addMessage(m);
}
/** @since 0.9.21 */
private void sendHaveAll() {
Message m = new Message();
m.type = Message.HAVE_ALL;
addMessage(m);
}
/** @since 0.9.21 */
private void sendHaveNone() {
Message m = new Message();
m.type = Message.HAVE_NONE;
addMessage(m);
}
/** @since 0.9.21 */
void sendReject(int piece, int begin, int length) {
Message m = new Message();
m.type = Message.REJECT;
m.piece = piece;
m.begin = begin;
m.length = length;
addMessage(m);
}
/**
* Unused
* @since 0.9.21
*/
void sendAllowedFast(int piece) {
Message m = new Message();
m.type = Message.ALLOWED_FAST;
m.piece = piece;
addMessage(m);
}
}

View File

@@ -33,6 +33,7 @@ import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicLong;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
@@ -87,8 +88,8 @@ class PeerCoordinator implements PeerListener
// final static int MAX_DOWNLOADERS = MAX_CONNECTIONS;
// int downloaders = 0;
private long uploaded;
private long downloaded;
private final AtomicLong uploaded = new AtomicLong();
private final AtomicLong downloaded = new AtomicLong();
final static int RATE_DEPTH = 3; // make following arrays RATE_DEPTH long
private final long uploaded_old[] = {-1,-1,-1};
private final long downloaded_old[] = {-1,-1,-1};
@@ -279,7 +280,7 @@ class PeerCoordinator implements PeerListener
*/
public long getUploaded()
{
return uploaded;
return uploaded.get();
}
/**
@@ -287,7 +288,7 @@ class PeerCoordinator implements PeerListener
* @since 0.9.15
*/
public void setUploaded(long up) {
uploaded = up;
uploaded.set(up);
}
/**
@@ -295,7 +296,7 @@ class PeerCoordinator implements PeerListener
*/
public long getDownloaded()
{
return downloaded;
return downloaded.get();
}
/**
@@ -321,16 +322,22 @@ class PeerCoordinator implements PeerListener
*/
public long getDownloadRate()
{
if (halted)
return 0;
return getRate(downloaded_old);
}
public long getUploadRate()
{
if (halted)
return 0;
return getRate(uploaded_old);
}
public long getCurrentUploadRate()
{
if (halted)
return 0;
// no need to synchronize, only one value
long r = uploaded_old[0];
if (r <= 0)
@@ -913,6 +920,7 @@ class PeerCoordinator implements PeerListener
* Returns a byte array containing the requested piece or null of
* the piece is unknown.
*
* @return bytes or null for errors such as not having the piece yet
* @throws RuntimeException on IOE getting the data
*/
public ByteArray gotRequest(Peer peer, int piece, int off, int len)
@@ -944,7 +952,7 @@ class PeerCoordinator implements PeerListener
*/
public void uploaded(Peer peer, int size)
{
uploaded += size;
uploaded.addAndGet(size);
//if (listener != null)
// listener.peerChange(this, peer);
@@ -955,7 +963,7 @@ class PeerCoordinator implements PeerListener
*/
public void downloaded(Peer peer, int size)
{
downloaded += size;
downloaded.addAndGet(size);
//if (listener != null)
// listener.peerChange(this, peer);
@@ -1003,9 +1011,21 @@ class PeerCoordinator implements PeerListener
}
else
{
// so we will try again
markUnrequested(peer, piece);
// just in case
removePartialPiece(piece);
// Oops. We didn't actually download this then... :(
downloaded -= metainfo.getPieceLength(piece);
_log.warn("Got BAD piece " + piece + "/" + metainfo.getPieces() + " from " + peer + " for " + metainfo.getName());
downloaded.addAndGet(0 - metainfo.getPieceLength(piece));
// Mark this peer as not having the piece. PeerState will update its bitfield.
for (Piece pc : wantedPieces) {
if (pc.getId() == piece) {
pc.removePeer(peer);
break;
}
}
if (_log.shouldWarn())
_log.warn("Got BAD piece " + piece + "/" + metainfo.getPieces() + " from " + peer + " for " + metainfo.getName());
return false; // No need to announce BAD piece to peers.
}
}
@@ -1134,8 +1154,9 @@ 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
* @param peer partials, must include the zero-offset (empty) ones too.
* No dup pieces, piece.setDownloaded() must be set.
* len field in Requests is ignored.
* @since 0.8.2
*/
public void savePartialPieces(Peer peer, List<Request> partials)

View File

@@ -21,6 +21,7 @@
package org.klomp.snark;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -155,12 +156,25 @@ class PeerState implements DataLoader
setInteresting(true);
}
void bitfieldMessage(byte[] bitmap)
{
synchronized(this)
{
if (_log.shouldLog(Log.DEBUG))
_log.debug(peer + " rcv bitfield");
void bitfieldMessage(byte[] bitmap) {
bitfieldMessage(bitmap, false);
}
/**
* @param bitmap null to use the isAll param
* @param isAll only if bitmap == null: true for have_all, false for have_none
* @since 0.9.21
*/
private void bitfieldMessage(byte[] bitmap, boolean isAll) {
if (_log.shouldLog(Log.DEBUG)) {
if (bitmap != null)
_log.debug(peer + " rcv bitfield bytes: " + bitmap.length);
else if (isAll)
_log.debug(peer + " rcv bitfield HAVE_ALL");
else
_log.debug(peer + " rcv bitfield HAVE_NONE");
}
synchronized(this) {
if (bitfield != null)
{
// XXX - Be liberal in what you accept?
@@ -172,10 +186,24 @@ class PeerState implements DataLoader
// XXX - Check for weird bitfield and disconnect?
// FIXME will have to regenerate the bitfield after we know exactly
// how many pieces there are, as we don't know how many spare bits there are.
if (metainfo == null)
bitfield = new BitField(bitmap, bitmap.length * 8);
else
bitfield = new BitField(bitmap, metainfo.getPieces());
if (metainfo == null) {
if (bitmap != null) {
bitfield = new BitField(bitmap, bitmap.length * 8);
} else {
// we can't handle this situation
if (_log.shouldLog(Log.WARN))
_log.warn("have_x w/o metainfo: " + isAll);
return;
}
} else {
if (bitmap != null) {
bitfield = new BitField(bitmap, metainfo.getPieces());
} else {
bitfield = new BitField(metainfo.getPieces());
if (isAll)
bitfield.setAll();
}
}
}
if (metainfo == null)
return;
@@ -198,14 +226,21 @@ class PeerState implements DataLoader
+ piece + ", " + begin + ", " + length + ") ");
if (metainfo == null)
return;
if (choking)
{
if (_log.shouldLog(Log.INFO))
_log.info("Request received, but choking " + peer);
if (choking) {
if (peer.supportsFast()) {
if (_log.shouldInfo())
_log.info("Request received, sending reject to choked " + peer);
out.sendReject(piece, begin, length);
} else {
if (_log.shouldInfo())
_log.info("Request received, but choking " + peer);
}
return;
}
}
// Sanity check
// There is no check here that we actually have the piece;
// this will be caught in loadData() below
if (piece < 0
|| piece >= metainfo.getPieces()
|| begin < 0
@@ -219,6 +254,8 @@ class PeerState implements DataLoader
+ ", " + begin
+ ", " + length
+ "' message from " + peer);
if (peer.supportsFast())
out.sendReject(piece, begin, length);
return;
}
@@ -227,8 +264,14 @@ class PeerState implements DataLoader
// Todo: limit number of requests also? (robert 64 x 4KB)
if (out.queuedBytes() + length > MAX_PIPELINE_BYTES)
{
if (_log.shouldLog(Log.WARN))
_log.warn("Discarding request over pipeline limit from " + peer);
if (peer.supportsFast()) {
if (_log.shouldWarn())
_log.warn("Rejecting request over pipeline limit from " + peer);
out.sendReject(piece, begin, length);
} else {
if (_log.shouldWarn())
_log.warn("Discarding request over pipeline limit from " + peer);
}
return;
}
@@ -243,7 +286,8 @@ class PeerState implements DataLoader
/**
* This is the callback that PeerConnectionOut calls
*
* @return bytes or null for errors
* @return bytes or null for errors such as not having the piece yet
* @throws RuntimeException on IOE getting the data
* @since 0.8.2
*/
public ByteArray loadData(int piece, int begin, int length) {
@@ -253,6 +297,8 @@ class PeerState implements DataLoader
// XXX - Protocol error-> diconnect?
if (_log.shouldLog(Log.WARN))
_log.warn("Got request for unknown piece: " + piece);
if (peer.supportsFast())
out.sendReject(piece, begin, length);
return null;
}
@@ -265,6 +311,8 @@ class PeerState implements DataLoader
+ ", " + begin
+ ", " + length
+ "' message from " + peer);
if (peer.supportsFast())
out.sendReject(piece, begin, length);
return null;
}
@@ -322,6 +370,11 @@ class PeerState implements DataLoader
{
if (_log.shouldLog(Log.WARN))
_log.warn("Got BAD " + req.getPiece() + " from " + peer);
synchronized(this) {
// so we don't ask again
if (bitfield != null)
bitfield.clear(req.getPiece());
}
}
}
@@ -455,7 +508,12 @@ class PeerState implements DataLoader
for (Integer p : pcs) {
Request req = getLowestOutstandingRequest(p.intValue());
if (req != null) {
req.getPartialPiece().setDownloaded(req.off);
PartialPiece pp = req.getPartialPiece();
synchronized(pp) {
int dl = pp.getDownloaded();
if (req.off != dl)
req = new Request(pp, dl, 1);
}
rv.add(req);
}
}
@@ -536,6 +594,89 @@ class PeerState implements DataLoader
listener.gotPort(peer, port, port + 1);
}
/////////// fast message handlers /////////
/**
* BEP 6
* Treated as "have" for now
* @since 0.9.21
*/
void suggestMessage(int piece) {
if (_log.shouldInfo())
_log.info("Handling suggest as have(" + piece + ") from " + peer);
haveMessage(piece);
}
/**
* BEP 6
* @param isAll true for have_all, false for have_none
* @since 0.9.21
*/
void haveMessage(boolean isAll) {
bitfieldMessage(null, isAll);
}
/**
* BEP 6
* If the peer rejects lower chunks but not higher ones, thus creating holes,
* we won't figure it out and the piece will fail, since we don't currently
* keep a chunk bitmap in PartialPiece.
* As long as the peer rejects all the chunks, or rejects only the last chunks,
* no holes are created and we will be fine. The reject messages may be in any order,
* just don't make a hole when it's over.
*
* @since 0.9.21
*/
void rejectMessage(int piece, int begin, int length) {
if (_log.shouldInfo())
_log.info("Got reject(" + piece + ',' + begin + ',' + length + ") from " + peer);
out.cancelRequest(piece, begin, length);
synchronized(this) {
Request deletedRequest = null;
// for this piece only
boolean haveMoreRequests = false;
for (Iterator<Request> iter = outstandingRequests.iterator(); iter.hasNext(); ) {
Request req = iter.next();
if (req.getPiece() == piece) {
if (req.off == begin && req.len == length) {
iter.remove();
deletedRequest = req;
} else {
haveMoreRequests = true;
}
}
}
if (deletedRequest != null && !haveMoreRequests) {
// We must return the piece to the coordinator
// Create a new fake request so we can set the offset correctly
PartialPiece pp = deletedRequest.getPartialPiece();
int downloaded = pp.getDownloaded();
Request req;
if (deletedRequest.off == downloaded)
req = deletedRequest;
else
req = new Request(pp, downloaded, 1);
List<Request> pcs = Collections.singletonList(req);
listener.savePartialPieces(this.peer, pcs);
if (_log.shouldWarn())
_log.warn("Returned to coord. w/ offset " + pp.getDownloaded() + " due to reject(" + piece + ',' + begin + ',' + length + ") from " + peer);
}
if (lastRequest != null && lastRequest.getPiece() == piece &&
lastRequest.off == begin && lastRequest.len == length)
lastRequest = null;
}
}
/**
* BEP 6
* Ignored for now
* @since 0.9.21
*/
void allowedFastMessage(int piece) {
if (_log.shouldInfo())
_log.info("Ignoring allowed_fast(" + piece + ") from " + peer);
}
void unknownMessage(int type, byte[] bs)
{
if (_log.shouldLog(Log.WARN))
@@ -543,6 +684,8 @@ class PeerState implements DataLoader
+ " length: " + bs.length);
}
/////////// end message handlers /////////
/**
* We now have this piece.
* Tell the peer and cancel any requests for the piece.

View File

@@ -43,13 +43,13 @@ class Request
*/
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.off = off;
this.len = len;
// Sanity check
if (off < 0 || len <= 0 || off + len > piece.getLength())
throw new IndexOutOfBoundsException("Illegal Request " + toString());
}
/**

View File

@@ -290,6 +290,7 @@ public class Snark
/**
* multitorrent
* @throws RuntimeException via fatal()
*/
public Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
StorageListener slistener, CoordinatorListener clistener,
@@ -304,6 +305,7 @@ public class Snark
* multitorrent
*
* @param baseFile if null, use rootDir/torrentName; if non-null, use it instead
* @throws RuntimeException via fatal()
* @since 0.9.11
*/
public Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
@@ -478,6 +480,7 @@ public class Snark
* @param torrent a fake name for now (not a file name)
* @param ih 20-byte info hash
* @param trackerURL may be null
* @throws RuntimeException via fatal()
* @since 0.8.4
*/
public Snark(I2PSnarkUtil util, String torrent, byte[] ih, String trackerURL,
@@ -531,6 +534,8 @@ public class Snark
/**
* Start up contacting peers and querying the tracker.
* Blocks if tunnel is not yet open.
*
* @throws RuntimeException via fatal()
*/
public synchronized void startTorrent() {
starting = true;
@@ -612,7 +617,6 @@ public class Snark
* @since 0.9.1
*/
public synchronized void stopTorrent(boolean fast) {
stopped = true;
TrackerClient tc = trackerclient;
if (tc != null)
tc.halt(fast);
@@ -620,17 +624,28 @@ public class Snark
if (pc != null)
pc.halt();
Storage st = storage;
if (!fast)
// HACK: Needed a way to distinguish between user-stop and
// shutdown-stop. stopTorrent(true) is in stopAllTorrents().
// (#766)
stopped = true;
if (st != null) {
boolean changed = storage.isChanged() || getUploaded() != savedUploaded;
// TODO: Cache the config-in-mem to compare vs config-on-disk
// (needed for auto-save to not double-save in some cases)
//boolean changed = storage.isChanged() || getUploaded() != savedUploaded;
boolean changed = true;
if (changed && completeListener != null)
completeListener.updateStatus(this);
try {
storage.close();
} catch (IOException ioe) {
System.out.println("Error closing " + torrent);
ioe.printStackTrace();
}
if (changed && completeListener != null)
completeListener.updateStatus(this);
}
if (fast)
// HACK: See above if(!fast)
stopped = true;
if (pc != null && _peerCoordinatorSet != null)
_peerCoordinatorSet.remove(pc);
if (_peerCoordinatorSet == null)

View File

@@ -27,6 +27,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.crypto.SHA1Hash;
import net.i2p.crypto.SigType;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
@@ -88,6 +89,7 @@ public class SnarkManager implements CompleteListener {
public static final String PROP_UPBW_MAX = "i2psnark.upbw.max";
public static final String PROP_DIR = "i2psnark.dir";
private static final String PROP_META_PREFIX = "i2psnark.zmeta.";
private static final String PROP_META_RUNNING = "running";
private static final String PROP_META_STAMP = "stamp";
private static final String PROP_META_BASE = "base";
private static final String PROP_META_BITFIELD = "bitfield";
@@ -233,7 +235,7 @@ public class SnarkManager implements CompleteListener {
// only if default instance
if ("i2psnark".equals(_contextName))
// delay until UpdateManager is there
_context.simpleScheduler().addEvent(new Register(), 4*60*1000);
_context.simpleTimer2().addEvent(new Register(), 4*60*1000);
// Not required, Jetty has a shutdown hook
//_context.addShutdownTask(new SnarkManagerShutdown());
_idleChecker = new IdleChecker(this, _peerCoordinatorSet);
@@ -537,6 +539,27 @@ public class SnarkManager implements CompleteListener {
return new File(subdir, hex + CONFIG_FILE_SUFFIX);
}
/**
* Extract the info hash from a config file name
* @return null for invalid name
* @since 0.9.20
*/
private static SHA1Hash configFileToInfoHash(File file) {
String name = file.getName();
if (name.length() != 40 + CONFIG_FILE_SUFFIX.length() || !name.endsWith(CONFIG_FILE_SUFFIX))
return null;
String hex = name.substring(0, 40);
byte[] ih = new byte[20];
try {
for (int i = 0; i < 20; i++) {
ih[i] = (byte) (Integer.parseInt(hex.substring(i*2, (i*2) + 2), 16) & 0xff);
}
} catch (NumberFormatException nfe) {
return null;
}
return new SHA1Hash(ih);
}
/** null to set initial defaults */
public void loadConfig(String filename) {
synchronized(_configLock) {
@@ -1224,7 +1247,7 @@ public class SnarkManager implements CompleteListener {
_log.info("New Snark, torrent: " + filename + " base: " + baseFile);
torrent = new Snark(_util, filename, null, -1, null, null, this,
_peerCoordinatorSet, _connectionAcceptor,
false, dataDir.getPath(), baseFile);
shouldAutoStart(), dataDir.getPath(), baseFile);
loadSavedFilePriorities(torrent);
synchronized (_snarks) {
_snarks.put(filename, torrent);
@@ -1248,7 +1271,16 @@ public class SnarkManager implements CompleteListener {
return;
}
// ok, snark created, now lets start it up or configure it further
if (!dontAutoStart && shouldAutoStart()) {
Properties config = getConfig(torrent);
boolean running;
String prop = config.getProperty(PROP_META_RUNNING);
if(prop == null || Boolean.parseBoolean(prop)) {
running = true;
} else {
running = false;
}
// Were we running last time?
if (!dontAutoStart && shouldAutoStart() && running) {
torrent.startTorrent();
addMessage(_("Torrent added and started: \"{0}\"", torrent.getBaseName()));
} else {
@@ -1356,6 +1388,7 @@ public class SnarkManager implements CompleteListener {
snark.stopTorrent();
_magnets.remove(snark.getName());
removeMagnetStatus(snark.getInfoHash());
removeTorrentStatus(snark);
}
/**
@@ -1406,9 +1439,10 @@ public class SnarkManager implements CompleteListener {
if (snark != null) {
addMessage(_("Torrent with this info hash is already running: {0}", snark.getBaseName()));
return false;
} else {
saveTorrentStatus(metainfo, bitfield, null, baseFile, true, 0, true); // no file priorities
}
// so addTorrent won't recheck
saveTorrentStatus(metainfo, bitfield, null, baseFile, true, 0); // no file priorities
// so addTorrent won't recheck
try {
locked_writeMetaInfo(metainfo, filename, areFilesPublic());
// hold the lock for a long time
@@ -1603,7 +1637,7 @@ public class SnarkManager implements CompleteListener {
return;
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(),
storage.getBase(), storage.getPreserveFileNames(),
snark.getUploaded());
snark.getUploaded(), snark.isStopped());
}
/**
@@ -1618,14 +1652,14 @@ public class SnarkManager implements CompleteListener {
* @param base may be null
*/
private void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities,
File base, boolean preserveNames, long uploaded) {
File base, boolean preserveNames, long uploaded, boolean stopped) {
synchronized (_configLock) {
locked_saveTorrentStatus(metainfo, bitfield, priorities, base, preserveNames, uploaded);
locked_saveTorrentStatus(metainfo, bitfield, priorities, base, preserveNames, uploaded, stopped);
}
}
private void locked_saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities,
File base, boolean preserveNames, long uploaded) {
File base, boolean preserveNames, long uploaded, boolean stopped) {
byte[] ih = metainfo.getInfoHash();
String bfs;
if (bitfield.complete()) {
@@ -1634,11 +1668,13 @@ public class SnarkManager implements CompleteListener {
byte[] bf = bitfield.getFieldBytes();
bfs = Base64.encode(bf);
}
boolean running = !stopped;
Properties config = getConfig(ih);
config.setProperty(PROP_META_STAMP, Long.toString(System.currentTimeMillis()));
config.setProperty(PROP_META_BITFIELD, bfs);
config.setProperty(PROP_META_PRESERVE_NAMES, Boolean.toString(preserveNames));
config.setProperty(PROP_META_UPLOADED, Long.toString(uploaded));
config.setProperty(PROP_META_RUNNING, Boolean.toString(running));
if (base != null)
config.setProperty(PROP_META_BASE, base.getAbsolutePath());
@@ -1684,11 +1720,18 @@ public class SnarkManager implements CompleteListener {
/**
* Remove the status of a torrent by removing the config file.
*/
public void removeTorrentStatus(MetaInfo metainfo) {
byte[] ih = metainfo.getInfoHash();
private void removeTorrentStatus(Snark snark) {
byte[] ih = snark.getInfoHash();
File conf = configFile(_configDir, ih);
synchronized (_configLock) {
conf.delete();
boolean ok = conf.delete();
if (ok) {
if (_log.shouldInfo())
_log.info("Deleted " + conf + " for " + snark.getName());
} else {
if (_log.shouldWarn())
_log.warn("Failed to delete " + conf + " for " + snark.getName());
}
File subdir = conf.getParentFile();
String[] files = subdir.list();
if (files != null && files.length == 0)
@@ -1696,6 +1739,62 @@ public class SnarkManager implements CompleteListener {
}
}
/**
* Remove all orphaned torrent status files, which weren't removed
* before 0.9.20, and could be left around after a manual delete also.
* Run this once at startup.
* @since 0.9.20
*/
private void cleanupTorrentStatus() {
Set<SHA1Hash> torrents = new HashSet<SHA1Hash>(32);
int found = 0;
int totalDeleted = 0;
synchronized (_snarks) {
for (Snark snark : _snarks.values()) {
torrents.add(new SHA1Hash(snark.getInfoHash()));
}
synchronized (_configLock) {
for (int i = 0; i < B64.length(); i++) {
File subdir = new File(_configDir, SUBDIR_PREFIX + B64.charAt(i));
File[] configs = subdir.listFiles();
if (configs == null)
continue;
int deleted = 0;
for (int j = 0; j < configs.length; j++) {
File config = configs[j];
SHA1Hash ih = configFileToInfoHash(config);
if (ih == null)
continue;
found++;
if (torrents.contains(ih)) {
if (_log.shouldInfo())
_log.info("Torrent for " + config + " exists");
} else {
boolean ok = config.delete();
if (ok) {
if (_log.shouldInfo())
_log.info("Deleted " + config + " for " + ih);
deleted++;
} else {
if (_log.shouldWarn())
_log.warn("Failed to delete " + config + " for " + ih);
}
}
}
if (deleted == configs.length) {
if (_log.shouldInfo())
_log.info("Deleting " + subdir);
subdir.delete();
}
totalDeleted += deleted;
}
}
}
if (_log.shouldInfo())
_log.info("Cleanup found " + torrents.size() + " torrents and " + found +
" configs, deleted " + totalDeleted + " old configs");
}
/**
* Just remember we have it
* @since 0.8.4
@@ -1753,7 +1852,8 @@ public class SnarkManager implements CompleteListener {
}
/**
* Stop the torrent, leaving it on the list of torrents unless told to remove it
* Stop the torrent, leaving it on the list of torrents unless told to remove it.
* If shouldRemove is true, removes the config file also.
*/
public Snark stopTorrent(String filename, boolean shouldRemove) {
File sfile = new File(filename);
@@ -1781,6 +1881,8 @@ public class SnarkManager implements CompleteListener {
// I2PServerSocket.accept() call properly?)
////_util.
}
if (shouldRemove)
removeTorrentStatus(torrent);
if (!wasStopped)
addMessage(_("Torrent stopped: \"{0}\"", torrent.getBaseName()));
}
@@ -1788,7 +1890,8 @@ public class SnarkManager implements CompleteListener {
}
/**
* Stop the torrent, leaving it on the list of torrents unless told to remove it
* Stop the torrent, leaving it on the list of torrents unless told to remove it.
* If shouldRemove is true, removes the config file also.
* @since 0.8.4
*/
public void stopTorrent(Snark torrent, boolean shouldRemove) {
@@ -1801,11 +1904,13 @@ public class SnarkManager implements CompleteListener {
torrent.stopTorrent();
if (!wasStopped)
addMessage(_("Torrent stopped: \"{0}\"", torrent.getBaseName()));
if (shouldRemove)
removeTorrentStatus(torrent);
}
/**
* Stop the torrent and delete the torrent file itself, but leaving the data
* behind.
* behind. Removes saved config file also.
* Holds the snarks lock to prevent interference from the DirMonitor.
*/
public void removeTorrent(String filename) {
@@ -1818,9 +1923,6 @@ public class SnarkManager implements CompleteListener {
File torrentFile = new File(filename);
torrentFile.delete();
}
Storage storage = torrent.getStorage();
if (storage != null)
removeTorrentStatus(storage.getMetaInfo());
addMessage(_("Torrent removed: \"{0}\"", torrent.getBaseName()));
}
@@ -1853,6 +1955,7 @@ public class SnarkManager implements CompleteListener {
_log.error("Error in the DirectoryMonitor", e);
}
if (doMagnets) {
// first run only
try {
addMagnets();
doMagnets = false;
@@ -1861,6 +1964,9 @@ public class SnarkManager implements CompleteListener {
}
if (!_snarks.isEmpty())
addMessage(_("Up bandwidth limit is {0} KBps", _util.getMaxUpBW()));
// To fix bug where files were left behind,
// but also good for when user removes snarks when i2p is not running
cleanupTorrentStatus();
}
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
}
@@ -1883,7 +1989,8 @@ public class SnarkManager implements CompleteListener {
if (meta.getFiles() != null)
buf.append('/');
buf.append("\">").append(base).append("</a>");
addMessageNoEscape(_("Download finished: {0}", buf.toString())); // + " (" + _("size: {0}B", DataHelper.formatSize2(len)) + ')');
if (snark.getDownloaded() > 0)
addMessageNoEscape(_("Download finished: {0}", buf.toString())); // + " (" + _("size: {0}B", DataHelper.formatSize2(len)) + ')');
updateStatus(snark);
}
@@ -1895,7 +2002,8 @@ public class SnarkManager implements CompleteListener {
Storage storage = snark.getStorage();
if (meta != null && storage != null)
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(),
storage.getBase(), storage.getPreserveFileNames(), snark.getUploaded());
storage.getBase(), storage.getPreserveFileNames(), snark.getUploaded(),
snark.isStopped());
}
/**
@@ -1918,7 +2026,8 @@ public class SnarkManager implements CompleteListener {
return null;
}
saveTorrentStatus(meta, storage.getBitField(), null,
storage.getBase(), storage.getPreserveFileNames(), 0);
storage.getBase(), storage.getPreserveFileNames(), 0,
snark.isStopped());
// temp for addMessage() in case canonical throws
String name = storage.getBaseName();
try {
@@ -2241,7 +2350,7 @@ public class SnarkManager implements CompleteListener {
* 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
* the tunnel won't actually be closed as the SimpleTimer2 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
@@ -2272,7 +2381,7 @@ public class SnarkManager implements CompleteListener {
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);
_context.simpleTimer2().addEvent(new Disconnector(), 60*1000);
addMessage(_("Closing I2P tunnel after notifying trackers."));
if (finalShutdown) {
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}

View File

@@ -20,6 +20,7 @@
package org.klomp.snark;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -50,7 +51,7 @@ import net.i2p.util.SystemVersion;
/**
* Maintains pieces on disk. Can be used to store and retrieve pieces.
*/
public class Storage
public class Storage implements Closeable
{
private final MetaInfo metainfo;
private final List<TorrentFile> _torrentFiles;

View File

@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
/**
* Holds different types that a bencoded byte array can represent.
@@ -208,7 +209,7 @@ public class BEValue
} else if (bin) {
buf.append(bs.length).append(" bytes: ").append(Base64.encode(bs));
} else {
buf.append('"').append(new String(bs)).append('"');
buf.append('"').append(DataHelper.getUTF8(bs)).append('"');
}
valueString = buf.toString();
} else

View File

@@ -87,6 +87,8 @@ abstract class PersistDHT {
out.println(ni.toPersistentString());
count++;
}
if (out.checkError())
throw new IOException("Failed write to " + file);
} catch (IOException ioe) {
if (log.shouldLog(Log.WARN))
log.warn("Error writing the DHT File", ioe);

View File

@@ -457,6 +457,7 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(" <a href=\"" + _contextPath + '/');
if (peerParam != null) {
// disable peer view
out.write(getQueryString(req, "", null, null));
out.write("\">");
tx = _("Hide Peers");
out.write(toThemeImg("hidepeers", tx, tx));
@@ -686,6 +687,17 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(", ");
out.write(ngettext("1 DHT peer", "{0} DHT peers", dhts));
}
}
String IPString = _manager.util().getOurIPString();
if(!IPString.equals("unknown")) {
// Only truncate if it's an actual dest
out.write(";&nbsp;");
out.write(_("Dest"));
out.write(":&nbsp;<tt>");
out.write(IPString.substring(0, 4));
out.write("</tt>");
}
if (dht != null) {
if (showDebug)
out.write(dht.renderStatusHTML());
}
@@ -1047,19 +1059,20 @@ public class I2PSnarkServlet extends BasicServlet {
File f = new File(name);
f.delete();
_manager.addMessage(_("Torrent file deleted: {0}", f.getAbsolutePath()));
List<List<String>> files = meta.getFiles();
String dataFile = snark.getBaseName();
f = new File(_manager.getDataDir(), dataFile);
if (files == null) { // single file torrent
if (f.delete())
_manager.addMessage(_("Data file deleted: {0}", f.getAbsolutePath()));
else
_manager.addMessage(_("Data file could not be deleted: {0}", f.getAbsolutePath()));
break;
}
Storage storage = snark.getStorage();
if (storage == null)
break;
List<List<String>> files = meta.getFiles();
if (files == null) { // single file torrent
for (File df : storage.getFiles()) {
// should be only one
if (df.delete())
_manager.addMessage(_("Data file deleted: {0}", df.getAbsolutePath()));
else
_manager.addMessage(_("Data file could not be deleted: {0}", df.getAbsolutePath()));
}
break;
}
// step 1 delete files
for (File df : storage.getFiles()) {
if (df.delete()) {
@@ -2269,13 +2282,13 @@ public class I2PSnarkServlet extends BasicServlet {
out.write("<tr><td>");
out.write(_("Inbound Settings"));
out.write(":<td>");
out.write(renderOptions(1, 8, 3, options.remove("inbound.quantity"), "inbound.quantity", TUNNEL));
out.write(renderOptions(1, 10, 3, options.remove("inbound.quantity"), "inbound.quantity", TUNNEL));
out.write("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
out.write(renderOptions(0, 4, 3, options.remove("inbound.length"), "inbound.length", HOP));
out.write("<tr><td>");
out.write(_("Outbound Settings"));
out.write(":<td>");
out.write(renderOptions(1, 8, 3, options.remove("outbound.quantity"), "outbound.quantity", TUNNEL));
out.write(renderOptions(1, 10, 3, options.remove("outbound.quantity"), "outbound.quantity", TUNNEL));
out.write("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
out.write(renderOptions(0, 4, 3, options.remove("outbound.length"), "outbound.length", HOP));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -26,73 +26,14 @@
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- this webapp doesn't actually use sessions or cookies -->
<session-config>
<session-timeout>
30
</session-timeout>
<cookie-config>
<http-only>true</http-only>
</cookie-config>
</session-config>
<!-- mime types not in mime.properties in the jetty 5.1.15 source -->
<mime-mapping>
<extension>mkv</extension>
<mime-type>video/x-matroska</mime-type>
</mime-mapping>
<mime-mapping>
<extension>wmv</extension>
<mime-type>video/x-ms-wmv</mime-type>
</mime-mapping>
<mime-mapping>
<extension>flv</extension>
<mime-type>video/x-flv</mime-type>
</mime-mapping>
<mime-mapping>
<extension>mp4</extension>
<mime-type>video/mp4</mime-type>
</mime-mapping>
<mime-mapping>
<extension>rar</extension>
<mime-type>application/rar</mime-type>
</mime-mapping>
<mime-mapping>
<extension>7z</extension>
<mime-type>application/x-7z-compressed</mime-type>
</mime-mapping>
<mime-mapping>
<extension>iso</extension>
<mime-type>application/x-iso9660-image</mime-type>
</mime-mapping>
<mime-mapping>
<extension>ico</extension>
<mime-type>image/x-icon</mime-type>
</mime-mapping>
<mime-mapping>
<extension>exe</extension>
<mime-type>application/x-msdos-program</mime-type>
</mime-mapping>
<mime-mapping>
<extension>flac</extension>
<mime-type>audio/flac</mime-type>
</mime-mapping>
<mime-mapping>
<extension>m4a</extension>
<mime-type>audio/mpeg</mime-type>
</mime-mapping>
<mime-mapping>
<extension>wma</extension>
<mime-type>audio/x-ms-wma</mime-type>
</mime-mapping>
</web-app>

View File

@@ -25,7 +25,7 @@ then
fi
# on windows, one must specify the path of commnad find
# since windows has its own retarded version of find.
# since windows has its own version of find.
if which find|grep -q -i windows ; then
export PATH=.:/bin:/usr/local/bin:$PATH
fi

View File

@@ -24,7 +24,7 @@ then
fi
# on windows, one must specify the path of commnad find
# since windows has its own retarded version of find.
# since windows has its own version of find.
if which find|grep -q -i windows ; then
export PATH=.:/bin:/usr/local/bin:$PATH
fi

View File

@@ -0,0 +1,372 @@
package net.i2p.i2ptunnel;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.CRC32;
import java.util.zip.Inflater;
import java.util.zip.InflaterOutputStream;
import net.i2p.data.DataHelper;
/**
* Gunzip implementation per
* <a href="http://www.faqs.org/rfcs/rfc1952.html">RFC 1952</a>, reusing
* java's standard CRC32 and Inflater and InflaterOutputStream implementations.
*
* Note that the underlying InflaterOutputStream cannot be reused after close(),
* so we don't have a Reusable version of this.
*
* Modified from net.i2p.util.ResettableGZIPInputStream to use Java 6 InflaterOutputstream
* @since 0.9.21
*/
class GunzipOutputStream extends InflaterOutputStream {
private static final int FOOTER_SIZE = 8; // CRC32 + ISIZE
private final CRC32 _crc32;
private final byte _buf1[] = new byte[1];
private boolean _complete;
private final byte _footer[] = new byte[FOOTER_SIZE];
private long _bytesReceived;
private long _bytesReceivedAtCompletion;
private enum HeaderState { MB1, MB2, CF, MT0, MT1, MT2, MT3, EF, OS, FLAGS,
EH1, EH2, EHDATA, NAME, COMMENT, CRC1, CRC2, DONE }
private HeaderState _state = HeaderState.MB1;
private int _flags;
private int _extHdrToRead;
/**
* Build a new Gunzip stream
*/
public GunzipOutputStream(OutputStream uncompressedStream) throws IOException {
super(uncompressedStream, new Inflater(true));
_crc32 = new CRC32();
}
@Override
public void write(int b) throws IOException {
_buf1[0] = (byte) b;
write(_buf1, 0, 1);
}
@Override
public void write(byte buf[]) throws IOException {
write(buf, 0, buf.length);
}
@Override
public void write(byte buf[], int off, int len) throws IOException {
if (_complete) {
// shortcircuit so the inflater doesn't try to refill
// with the footer's data (which would fail, causing ZLIB err)
return;
}
boolean isFinished = inf.finished();
for (int i = off; i < off + len; i++) {
if (!isFinished) {
if (_state != HeaderState.DONE) {
verifyHeader(buf[i]);
continue;
}
// ensure we call the same method variant so we don't depend on underlying implementation
super.write(buf, i, 1);
if (inf.finished()) {
isFinished = true;
_bytesReceivedAtCompletion = _bytesReceived;
}
}
_footer[(int) (_bytesReceived++ % FOOTER_SIZE)] = buf[i];
if (isFinished) {
long footerSize = _bytesReceivedAtCompletion - _bytesReceived;
// could be at 7 or 8...
// we write the first byte of the footer to the Inflater if necessary...
// see comments in ResettableGZIPInputStream for details
if (footerSize >= FOOTER_SIZE - 1) {
try {
verifyFooter();
inf.reset(); // so it doesn't bitch about missing data...
_complete = true;
return;
} catch (IOException ioe) {
// failed at 7, retry at 8
if (footerSize == FOOTER_SIZE - 1 && i < off + len - 1)
continue;
_complete = true;
throw ioe;
}
}
}
}
}
/**
* Inflater statistic
*/
public long getTotalRead() {
try {
return inf.getBytesRead();
} catch (Exception e) {
return 0;
}
}
/**
* Inflater statistic
*/
public long getTotalExpanded() {
try {
return inf.getBytesWritten();
} catch (Exception e) {
// possible NPE in some implementations
return 0;
}
}
/**
* Inflater statistic
*/
public long getRemaining() {
try {
return inf.getRemaining();
} catch (Exception e) {
// possible NPE in some implementations
return 0;
}
}
/**
* Inflater statistic
*/
public boolean getFinished() {
try {
return inf.finished();
} catch (Exception e) {
// possible NPE in some implementations
return true;
}
}
@Override
public void close() throws IOException {
_complete = true;
_state = HeaderState.DONE;
super.close();
}
@Override
public String toString() {
return "GOS read: " + getTotalRead() + " expanded: " + getTotalExpanded() + " remaining: " + getRemaining() + " finished: " + getFinished();
}
/**
* @throws IOException on CRC or length check fail
*/
private void verifyFooter() throws IOException {
int idx = (int) (_bytesReceivedAtCompletion % FOOTER_SIZE);
byte[] footer;
if (idx == 0) {
footer = _footer;
} else {
footer = new byte[FOOTER_SIZE];
for (int i = 0; i < FOOTER_SIZE; i++) {
footer[i] = _footer[(int) ((_bytesReceivedAtCompletion + i) % FOOTER_SIZE)];
}
}
long actualSize = inf.getTotalOut();
long expectedSize = DataHelper.fromLongLE(footer, 4, 4);
if (expectedSize != actualSize)
throw new IOException("gunzip expected " + expectedSize + " bytes, got " + actualSize);
long actualCRC = _crc32.getValue();
long expectedCRC = DataHelper.fromLongLE(footer, 0, 4);
if (expectedCRC != actualCRC)
throw new IOException("gunzip CRC fail expected 0x" + Long.toHexString(expectedCRC) +
" bytes, got 0x" + Long.toHexString(actualCRC));
}
/**
* Make sure the header is valid, throwing an IOException if it is bad.
* Pushes through the state machine, checking as we go.
* Call for each byte until HeaderState is DONE.
*/
private void verifyHeader(byte b) throws IOException {
int c = b & 0xff;
switch (_state) {
case MB1:
if (c != 0x1F) throw new IOException("First magic byte was wrong [" + c + "]");
_state = HeaderState.MB2;
break;
case MB2:
if (c != 0x8B) throw new IOException("Second magic byte was wrong [" + c + "]");
_state = HeaderState.CF;
break;
case CF:
if (c != 0x08) throw new IOException("Compression format is invalid [" + c + "]");
_state = HeaderState.FLAGS;
break;
case FLAGS:
_flags = c;
_state = HeaderState.MT0;
break;
case MT0:
// ignore
_state = HeaderState.MT1;
break;
case MT1:
// ignore
_state = HeaderState.MT2;
break;
case MT2:
// ignore
_state = HeaderState.MT3;
break;
case MT3:
// ignore
_state = HeaderState.EF;
break;
case EF:
if ( (c != 0x00) && (c != 0x02) && (c != 0x04) )
throw new IOException("Invalid extended flags [" + c + "]");
_state = HeaderState.OS;
break;
case OS:
// ignore
if (0 != (_flags & (1<<5)))
_state = HeaderState.EH1;
else if (0 != (_flags & (1<<4)))
_state = HeaderState.NAME;
else if (0 != (_flags & (1<<3)))
_state = HeaderState.COMMENT;
else if (0 != (_flags & (1<<6)))
_state = HeaderState.CRC1;
else
_state = HeaderState.DONE;
break;
case EH1:
_extHdrToRead = c;
_state = HeaderState.EH2;
break;
case EH2:
_extHdrToRead += (c << 8);
if (_extHdrToRead > 0)
_state = HeaderState.EHDATA;
else if (0 != (_flags & (1<<4)))
_state = HeaderState.NAME;
if (0 != (_flags & (1<<3)))
_state = HeaderState.COMMENT;
else if (0 != (_flags & (1<<6)))
_state = HeaderState.CRC1;
else
_state = HeaderState.DONE;
break;
case EHDATA:
// ignore
if (--_extHdrToRead <= 0) {
if (0 != (_flags & (1<<4)))
_state = HeaderState.NAME;
if (0 != (_flags & (1<<3)))
_state = HeaderState.COMMENT;
else if (0 != (_flags & (1<<6)))
_state = HeaderState.CRC1;
else
_state = HeaderState.DONE;
}
break;
case NAME:
// ignore
if (c == 0) {
if (0 != (_flags & (1<<3)))
_state = HeaderState.COMMENT;
else if (0 != (_flags & (1<<6)))
_state = HeaderState.CRC1;
else
_state = HeaderState.DONE;
}
break;
case COMMENT:
// ignore
if (c == 0) {
if (0 != (_flags & (1<<6)))
_state = HeaderState.CRC1;
else
_state = HeaderState.DONE;
}
break;
case CRC1:
// ignore
_state = HeaderState.CRC2;
break;
case CRC2:
// ignore
_state = HeaderState.DONE;
break;
case DONE:
default:
break;
}
}
/****
public static void main(String args[]) {
java.util.Random r = new java.util.Random();
for (int i = 0; i < 1050; i++) {
byte[] b = new byte[i];
r.nextBytes(b);
if (!test(b)) return;
}
for (int i = 1; i < 64*1024; i+= 29) {
byte[] b = new byte[i];
r.nextBytes(b);
if (!test(b)) return;
}
}
private static boolean test(byte[] b) {
int size = b.length;
try {
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(size);
java.util.zip.GZIPOutputStream o = new java.util.zip.GZIPOutputStream(baos);
o.write(b);
o.finish();
o.flush();
byte compressed[] = baos.toByteArray();
java.io.ByteArrayOutputStream baos2 = new java.io.ByteArrayOutputStream(size);
GunzipOutputStream out = new GunzipOutputStream(baos2);
out.write(compressed);
byte rv[] = baos2.toByteArray();
if (rv.length != b.length)
throw new RuntimeException("read length: " + rv.length + " expected: " + b.length);
if (!net.i2p.data.DataHelper.eq(rv, 0, b, 0, b.length)) {
throw new RuntimeException("foo, read=" + rv.length);
} else {
System.out.println("match, w00t @ " + size);
return true;
}
} catch (Exception e) {
System.out.println("Error dealing with size=" + size + ": " + e.getMessage());
e.printStackTrace();
return false;
}
}
****/
}

View File

@@ -10,20 +10,14 @@ package net.i2p.i2ptunnel;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Locale;
import java.util.concurrent.RejectedExecutionException;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
import net.i2p.util.BigPipedInputStream;
import net.i2p.data.DataHelper;
import net.i2p.util.ByteCache;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
import net.i2p.util.ReusableGZIPInputStream;
/**
* This does the transparent gzip decompression on the client side.
@@ -152,9 +146,11 @@ class HTTPResponseOutputStream extends FilterOutputStream {
for (int i = 0; i < _headerBuffer.getValid(); i++) {
if (isNL(_headerBuffer.getData()[i])) {
if (lastEnd == -1) {
responseLine = new String(_headerBuffer.getData(), 0, i+1); // includes NL
responseLine = DataHelper.getUTF8(_headerBuffer.getData(), 0, i+1); // includes NL
responseLine = filterResponseLine(responseLine);
responseLine = (responseLine.trim() + "\r\n");
if (_log.shouldLog(Log.INFO))
_log.info("Response: " + responseLine.trim());
out.write(responseLine.getBytes());
} else {
for (int j = lastEnd+1; j < i; j++) {
@@ -163,12 +159,12 @@ class HTTPResponseOutputStream extends FilterOutputStream {
int valLen = i-(j+1);
if ( (keyLen <= 0) || (valLen < 0) )
throw new IOException("Invalid header @ " + j);
String key = new String(_headerBuffer.getData(), lastEnd+1, keyLen);
String key = DataHelper.getUTF8(_headerBuffer.getData(), lastEnd+1, keyLen);
String val = null;
if (valLen == 0)
val = "";
else
val = new String(_headerBuffer.getData(), j+2, valLen).trim();
val = DataHelper.getUTF8(_headerBuffer.getData(), j+2, valLen).trim();
if (_log.shouldLog(Log.INFO))
_log.info("Response header [" + key + "] = [" + val + "]");
@@ -197,9 +193,10 @@ class HTTPResponseOutputStream extends FilterOutputStream {
} else if ("set-cookie".equals(lcKey)) {
String lcVal = val.toLowerCase(Locale.US);
if (lcVal.contains("domain=b32.i2p") ||
lcVal.contains("domain=.b32.i2p")) {
// Strip privacy-damaging "supercookie" for b32.i2p
// Let's presume the user agent ignores a cookie for "i2p"
lcVal.contains("domain=.b32.i2p") ||
lcVal.contains("domain=i2p") ||
lcVal.contains("domain=.i2p")) {
// Strip privacy-damaging "supercookies" for i2p and b32.i2p
// See RFC 6265 and http://publicsuffix.org/
if (_log.shouldLog(Log.INFO))
_log.info("Stripping \"" + key + ": " + val + "\" from response ");
@@ -245,94 +242,19 @@ class HTTPResponseOutputStream extends FilterOutputStream {
@Override
public void close() throws IOException {
out.close();
if (_log.shouldLog(Log.INFO))
_log.info("Closing " + out + " threaded?? " + shouldCompress(), new Exception("I did it"));
synchronized(this) {
// synch with changing out field below
super.close();
}
}
protected void beginProcessing() throws IOException {
//out.flush();
PipedInputStream pi = BigPipedInputStream.getInstance();
PipedOutputStream po = new PipedOutputStream(pi);
Runnable r = new Pusher(pi, out);
out = po;
// TODO we should be able to do this inline somehow
TunnelControllerGroup tcg = TunnelControllerGroup.getInstance();
if (tcg != null) {
// Run in the client thread pool, as there should be an unused thread
// there after the accept().
// Overridden in I2PTunnelHTTPServer, where it does not use the client pool.
try {
tcg.getClientExecutor().execute(r);
} catch (RejectedExecutionException ree) {
// shouldn't happen
throw ree;
}
} else {
// Fallback in case TCG.getInstance() is null, never instantiated
// and we were not started by TCG.
// Maybe a plugin loaded before TCG? Should be rare.
Thread t = new I2PAppThread(r, "Pusher");
t.start();
}
}
private class Pusher implements Runnable {
private final InputStream _inRaw;
private final OutputStream _out;
public Pusher(InputStream in, OutputStream out) {
_inRaw = in;
_out = out;
}
public void run() {
ReusableGZIPInputStream _in = ReusableGZIPInputStream.acquire();
long written = 0;
ByteArray ba = null;
try {
// blocking
_in.initialize(_inRaw);
ba = _cache.acquire();
byte buf[] = ba.getData();
int read = -1;
while ( (read = _in.read(buf)) != -1) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Read " + read + " and writing it to the browser/streams");
_out.write(buf, 0, read);
_out.flush();
written += read;
}
if (_log.shouldLog(Log.INFO))
_log.info("Decompressed: " + written + ", " + _in.getTotalRead() + "/" + _in.getTotalExpanded());
} catch (IOException ioe) {
if (_log.shouldLog(Log.WARN))
_log.warn("Error decompressing: " + written + ", " + _in.getTotalRead() + "/" + _in.getTotalExpanded(), ioe);
} catch (OutOfMemoryError oom) {
_log.error("OOM in HTTP Decompressor", oom);
} finally {
if (_log.shouldLog(Log.INFO) && (_in != null))
_log.info("After decompression, written=" + written +
" read=" + _in.getTotalRead()
+ ", expanded=" + _in.getTotalExpanded() + ", remaining=" + _in.getRemaining()
+ ", finished=" + _in.getFinished());
if (ba != null)
_cache.release(ba);
if (_out != null) try {
_out.close();
} catch (IOException ioe) {}
}
if (_in != null) {
double compressed = _in.getTotalRead();
double expanded = _in.getTotalExpanded();
ReusableGZIPInputStream.release(_in);
if (compressed > 0 && expanded > 0) {
// only update the stats if we did something
double ratio = compressed/expanded;
_context.statManager().addRateData("i2ptunnel.httpCompressionRatio", (int)(100d*ratio));
_context.statManager().addRateData("i2ptunnel.httpCompressed", (long)compressed);
_context.statManager().addRateData("i2ptunnel.httpExpanded", (long)expanded);
}
}
OutputStream po = new GunzipOutputStream(out);
synchronized(this) {
out = po;
}
}

View File

@@ -35,7 +35,6 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -887,13 +886,13 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
if (portNum <= 0)
throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]);
I2PTunnelTask task;
ownDest = !isShared;
try {
String privateKeyFile = null;
if (args.length >= 4)
privateKeyFile = args[3];
task = new I2PTunnelClient(portNum, args[1], l, ownDest, this, this, privateKeyFile);
I2PTunnelClientBase task = new I2PTunnelClient(portNum, args[1], l, ownDest, this, this, privateKeyFile);
task.startRunning();
addtask(task);
notifyEvent("clientTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -966,10 +965,10 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
}
}
I2PTunnelTask task;
ownDest = !isShared;
try {
task = new I2PTunnelHTTPClient(clientPort, l, ownDest, proxy, this, this);
I2PTunnelClientBase task = new I2PTunnelHTTPClient(clientPort, l, ownDest, proxy, this, this);
task.startRunning();
addtask(task);
notifyEvent("httpclientTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -1035,10 +1034,10 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
}
}
I2PTunnelTask task;
ownDest = !isShared;
try {
task = new I2PTunnelConnectClient(_port, l, ownDest, proxy, this, this);
I2PTunnelClientBase task = new I2PTunnelConnectClient(_port, l, ownDest, proxy, this, this);
task.startRunning();
addtask(task);
} catch (IllegalArgumentException iae) {
String msg = "Invalid I2PTunnel configuration to create a CONNECT client connecting to the router at " + host + ':'+ port +
@@ -1097,13 +1096,13 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
}
}
I2PTunnelTask task;
ownDest = !isShared;
try {
String privateKeyFile = null;
if (args.length >= 4)
privateKeyFile = args[3];
task = new I2PTunnelIRCClient(_port, args[1], l, ownDest, this, this, privateKeyFile);
I2PTunnelClientBase task = new I2PTunnelIRCClient(_port, args[1], l, ownDest, this, this, privateKeyFile);
task.startRunning();
addtask(task);
notifyEvent("ircclientTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -1160,7 +1159,8 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
if (args.length == 3)
privateKeyFile = args[2];
try {
I2PTunnelTask task = new I2PSOCKSTunnel(_port, l, ownDest, this, this, privateKeyFile);
I2PTunnelClientBase task = new I2PSOCKSTunnel(_port, l, ownDest, this, this, privateKeyFile);
task.startRunning();
addtask(task);
notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -1207,7 +1207,8 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
if (args.length == 3)
privateKeyFile = args[2];
try {
I2PTunnelTask task = new I2PSOCKSIRCTunnel(_port, l, ownDest, this, this, privateKeyFile);
I2PTunnelClientBase task = new I2PSOCKSIRCTunnel(_port, l, ownDest, this, this, privateKeyFile);
task.startRunning();
addtask(task);
notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -1326,25 +1327,30 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
* @param l logger to receive events and output
*/
private void runConfig(String args[], Logging l) {
if (args.length >= 2) {
if (args.length >= 1) {
int i = 0;
if (args[0].equals("-s")) {
boolean ssl = args[0].equals("-s");
if (ssl) {
_clientOptions.setProperty("i2cp.SSL", "true");
i++;
} else {
_clientOptions.remove("i2cp.SSL");
}
host = args[i++];
listenHost = host;
port = args[i];
if (i < args.length) {
host = args[i++];
listenHost = host;
}
if (i < args.length)
port = args[i];
l.log("New setting: " + host + ' ' + port + (ssl ? " SSL" : " non-SSL"));
notifyEvent("configResult", "ok");
} else {
boolean ssl = Boolean.parseBoolean(_clientOptions.getProperty("i2cp.SSL"));
l.log("Usage:\n" +
" config [-s] <i2phost> <i2pport>\n" +
" sets the connection to the i2p router.\n" +
"Current setting:\n" +
" " + host + ' ' + port + (ssl ? " SSL" : ""));
" config [-s] [<i2phost>] [<i2pport>]\n" +
" Sets the address and port of the I2P router.\n" +
" Use -s for SSL.\n" +
"Current setting: " + host + ' ' + port + (ssl ? " SSL" : " non-SSL"));
notifyEvent("configResult", "error");
}
}
@@ -1510,7 +1516,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
if (tasks.isEmpty()) {
System.exit(0);
}
l.log("There are running tasks. Try 'list'.");
l.log("There are running tasks. Try 'list' or 'close all'.");
//notifyEvent("quitResult", "error");
}
@@ -1598,7 +1604,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
private void runRun(String args[], Logging l) {
if (args.length == 1) {
try {
BufferedReader br = new BufferedReader(new FileReader(args[0]));
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(args[0]), "UTF-8"));
String line;
while ((line = br.readLine()) != null) {
runCommand(line, l);
@@ -1670,7 +1676,8 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
if (!_clientOptions.containsKey("outbound.nickname"))
_clientOptions.setProperty("outbound.nickname", "I2Ping");
}
I2PTunnelTask task = new I2Ping(l, ownDest, this, this);
I2PTunnelClientBase task = new I2Ping(l, ownDest, this, this);
task.startRunning();
addtask(task);
notifyEvent("pingTaskId", Integer.valueOf(task.getId()));
} else {
@@ -1747,8 +1754,8 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
*/
public void log(String s) {
System.out.println(s);
if (_log.shouldLog(Log.INFO))
_log.info(getPrefix() + "Display: " + s);
//if (_log.shouldLog(Log.INFO))
// _log.info(getPrefix() + "Display: " + s);
}
/**
@@ -1766,8 +1773,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
l.log("Generating new keys...");
I2PClient client = I2PClientFactory.createClient();
Destination d = client.createDestination(writeTo);
l.log("Secret key saved.\n" +
"Public key: " + d.toBase64());
l.log("New destination: " + d.toBase32());
writeTo.flush();
writeTo.close();
writePubKey(d, pubDest, l);
@@ -1790,7 +1796,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
try {
Destination d = new Destination();
d.readBytes(readFrom);
l.log("Public key: " + d.toBase64());
l.log("Destination: " + d.toBase32());
readFrom.close();
writePubKey(d, pubDest, l);
} catch (I2PException ex) {
@@ -1805,7 +1811,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
* Deprecated - only used by CLI
*
* @param d Destination to write
* @param o stream to write the destination to
* @param o stream to write the destination to, or null for noop
* @param l logger to send messages to
*/
private static void writePubKey(Destination d, OutputStream o, Logging l) throws I2PException, IOException {

View File

@@ -32,6 +32,9 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
protected long readTimeout = DEFAULT_READ_TIMEOUT;
/**
* As of 0.9.20 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
*
* @param destinations peers we target, comma- or space-separated. Since 0.9.9, each dest may be appended with :port
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
@@ -44,11 +47,6 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
tunnel, pkf);
_addrs = new ArrayList<I2PSocketAddress>(1);
if (waitEventValue("openBaseClientResult").equals("error")) {
notifyEvent("openClientResult", "error");
return;
}
dests = new ArrayList<Destination>(1);
buildAddresses(destinations);
@@ -68,9 +66,6 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
}
setName(getLocalPort() + " -> " + destinations);
startRunning();
notifyEvent("openClientResult", "ok");
}

View File

@@ -25,11 +25,14 @@ import javax.net.ssl.SSLServerSocketFactory;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.I2PClient;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManagerFactory;
import net.i2p.client.streaming.I2PSocketOptions;
import net.i2p.crypto.SigType;
import net.i2p.data.Destination;
import net.i2p.util.EventDispatcher;
import net.i2p.util.I2PAppThread;
@@ -52,7 +55,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
protected boolean _ownDest;
protected Destination dest;
private int localPort;
private volatile int localPort;
private final String _handlerName;
/**
* Protected for I2Ping since 0.9.11. Not for use outside package.
@@ -75,11 +79,24 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
private volatile ThreadPoolExecutor _executor;
/** this is ONLY for shared clients */
private static I2PSocketManager socketManager;
/**
* Only destroy and replace a static shared client socket manager if it's been connected before
* @since 0.9.20
*/
private enum SocketManagerState { INIT, CONNECTED }
private static SocketManagerState _socketManagerState = SocketManagerState.INIT;
public static final String PROP_USE_SSL = I2PTunnelServer.PROP_USE_SSL;
/**
* This constructor always starts the tunnel (ignoring the i2cp.delayOpen option).
* It is used to add a client to an existing socket manager.
* This constructor is used to add a client to an existing socket manager.
* <p/>
* As of 0.9.21 this does NOT open the local socket. You MUST call
* {@link #startRunning()} for that. The local socket will be opened
* immediately (ignoring the <code>i2cp.delayOpen</code> option).
*
* @param localPort if 0, use any port, get actual port selected with getLocalPort()
* @param sktMgr the existing socket manager
@@ -91,41 +108,24 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
chained = true;
sockMgr = sktMgr;
_clientId = clientId;
_handlerName = "chained";
this.localPort = localPort;
this.l = l;
_ownDest = true; // == ! shared client
_context = tunnel.getContext();
_context.statManager().createRateStat("i2ptunnel.client.closeBacklog", "How many pending sockets remain when we close one due to backlog?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.client.closeNoBacklog", "How many pending sockets remain when it was removed prior to backlog timeout?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
initStats();
_log = _context.logManager().getLog(getClass());
Thread t = new I2PAppThread(this, "Client " + tunnel.listenHost + ':' + localPort);
t.start();
open = true;
synchronized (this) {
while (!listenerReady && open) {
try {
wait();
} catch (InterruptedException e) {
// ignore
}
}
}
if (open && listenerReady) {
l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
notifyEvent("openBaseClientResult", "ok");
} else {
l.log("Client error for " + tunnel.listenHost + ':' + localPort + ", check logs");
notifyEvent("openBaseClientResult", "error");
}
}
/**
* The main constructor.
* This may take a LONG time if building and starting a new manager.
* <p/>
* As of 0.9.21 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
* <p/>
* (0.9.20 claimed to be fast, but due to a bug it DID connect the manager
* to the router. It did NOT open the local socket however, so it was still
* necessary to call startRunning() for that.)
*
* @param localPort if 0, use any port, get actual port selected with getLocalPort()
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -139,7 +139,13 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
/**
* Use this to build a client with a persistent private key.
* This may take a LONG time if building and starting a new manager.
* <p/>
* As of 0.9.21 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
* <p/>
* (0.9.20 claimed to be fast, but due to a bug it DID connect the manager
* to the router. It did NOT open the local socket however, so it was still
* necessary to call startRunning() for that.)
*
* @param localPort if 0, use any port, get actual port selected with getLocalPort()
* @param pkf Path to the private key file, or null to generate a transient key
@@ -155,13 +161,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
this.localPort = localPort;
this.l = l;
_ownDest = ownDest; // == ! shared client
_handlerName = handlerName;
_context = tunnel.getContext();
_context.statManager().createRateStat("i2ptunnel.client.closeBacklog", "How many pending sockets remain when we close one due to backlog?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.client.closeNoBacklog", "How many pending sockets remain when it was removed prior to backlog timeout?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
initStats();
_log = _context.logManager().getLog(getClass());
// normalize path so we can find it
@@ -180,54 +183,19 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
tunnel.getClientOptions().setProperty("i2cp.dontPublishLeaseSet", "true");
if (tunnel.getClientOptions().getProperty("i2p.streaming.answerPings") == null)
tunnel.getClientOptions().setProperty("i2p.streaming.answerPings", "false");
boolean openNow = !Boolean.parseBoolean(tunnel.getClientOptions().getProperty("i2cp.delayOpen"));
if (openNow) {
while (sockMgr == null) {
verifySocketManager();
if (sockMgr == null) {
_log.error("Unable to connect to router and build tunnels for " + handlerName);
// FIXME there is a loop in buildSocketManager(), do we really need another one here?
// no matter, buildSocketManager() now throws an IllegalArgumentException
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
}
}
// can't be null unless we limit the loop above
//if (sockMgr == null) {
// l.log("Invalid I2CP configuration");
// throw new IllegalArgumentException("Socket manager could not be created");
//}
l.log("Tunnels ready for client: " + handlerName);
} // else delay creating session until createI2PSocket() is called
Thread t = new I2PAppThread(this);
t.setName("Client " + _clientId);
t.start();
open = true;
synchronized (this) {
while (!listenerReady && open) {
try {
wait();
} catch (InterruptedException e) {
// ignore
}
}
}
if (open && listenerReady) {
if (openNow)
l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort);
else
l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort + ", delaying tunnel open until required");
notifyEvent("openBaseClientResult", "ok");
} else {
l.log("Client error for " + tunnel.listenHost + ':' + localPort + ", check logs");
notifyEvent("openBaseClientResult", "error");
}
}
private void initStats() {
_context.statManager().createRateStat("i2ptunnel.client.closeBacklog", "How many pending sockets remain when we close one due to backlog?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.client.closeNoBacklog", "How many pending sockets remain when it was removed prior to backlog timeout?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
}
/**
* Create the manager if it doesn't exist, AND connect it to the router and
* build tunnels.
*
* Sets the this.sockMgr field if it is null, or if we want a new one.
* This may take a LONG time if building a new manager.
*
@@ -269,15 +237,13 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
this.sockMgr = getSocketManager();
}
}
connectManager();
}
/** this is ONLY for shared clients */
private static I2PSocketManager socketManager;
/**
* This is ONLY for shared clients.
* This may take a LONG time if building a new manager.
* As of 0.9.20 this is fast, and does NOT connect the manager to the router.
* Call verifySocketManager() for that.
*
* @return non-null
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -289,7 +255,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
/**
* This is ONLY for shared clients.
* This may take a LONG time if building a new manager.
* As of 0.9.20 this is fast, and does NOT connect the manager to the router.
* Call verifySocketManager() for that.
*
* @return non-null
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -301,7 +268,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
/**
* This is ONLY for shared clients.
* This may take a LONG time if building a new manager.
* As of 0.9.20 this is fast, and does NOT connect the manager to the router.
* Call verifySocketManager() for that.
*
* @return non-null
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -312,14 +280,19 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
Log _log = tunnel.getContext().logManager().getLog(I2PTunnelClientBase.class);
if (socketManager != null && !socketManager.isDestroyed()) {
I2PSession s = socketManager.getSession();
if (s.isClosed()) {
if (s.isClosed() && _socketManagerState != SocketManagerState.INIT) {
if (_log.shouldLog(Log.INFO))
_log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Building a new socket manager since the old one closed [s=" + s + "]");
tunnel.removeSession(s);
// make sure the old one is closed
socketManager.destroySocketManager();
_socketManagerState = SocketManagerState.INIT;
// We could be here a LONG time, holding the lock
socketManager = buildSocketManager(tunnel, pkf);
// FIXME may not be the right place for this
I2PSession sub = addSubsession(tunnel);
if (sub != null && _log.shouldLog(Log.WARN))
_log.warn("Added subsession " + sub);
} else {
if (_log.shouldLog(Log.INFO))
_log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Not building a new socket manager since the old one is open [s=" + s + "]");
@@ -332,10 +305,41 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
if (_log.shouldLog(Log.INFO))
_log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Building a new socket manager since there is no other one");
socketManager = buildSocketManager(tunnel, pkf);
I2PSession sub = addSubsession(tunnel);
if (sub != null && _log.shouldLog(Log.WARN))
_log.warn("Added subsession " + sub);
}
return socketManager;
}
/**
* Add a subsession to a shared client if necessary.
*
* @since 0.9.20
*/
protected static synchronized I2PSession addSubsession(I2PTunnel tunnel) {
I2PSession sess = socketManager.getSession();
if (sess.getMyDestination().getSigType() == SigType.DSA_SHA1)
return null;
Properties props = new Properties();
props.putAll(tunnel.getClientOptions());
String name = props.getProperty("inbound.nickname");
if (name != null)
props.setProperty("inbound.nickname", name + " (DSA)");
name = props.getProperty("outbound.nickname");
if (name != null)
props.setProperty("outbound.nickname", name + " (DSA)");
props.setProperty(I2PClient.PROP_SIGTYPE, "DSA_SHA1");
try {
return socketManager.addSubsession(null, props);
} catch (I2PSessionException ise) {
Log log = tunnel.getContext().logManager().getLog(I2PTunnelClientBase.class);
if (log.shouldLog(Log.WARN))
log.warn("Failed to add subssession", ise);
return null;
}
}
/**
* Kill the shared client, so that on restart in android
* we won't latch onto the old one
@@ -347,7 +351,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
/**
* This may take a LONG time.
* For NON-SHARED clients (ownDest = true).
*
* As of 0.9.20 this is fast, and does NOT connect the manager to the router.
* Call verifySocketManager() for that.
*
* @return non-null
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -356,8 +363,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
protected I2PSocketManager buildSocketManager() {
return buildSocketManager(getTunnel(), this.privKeyFile, this.l);
}
/**
* This may take a LONG time.
* As of 0.9.20 this is fast, and does NOT connect the manager to the router.
* Call verifySocketManager() for that.
*
* @return non-null
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@@ -371,7 +380,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
private static final int MAX_RETRIES = 4;
/**
* This may take a LONG time.
* As of 0.9.20 this is fast, and does NOT connect the manager to the router.
* Call verifySocketManager() for that.
*
* @param pkf absolute path or null
* @return non-null
@@ -383,7 +393,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
/**
* This may take a LONG time.
* As of 0.9.20 this is fast, and does NOT connect the manager to the router.
* Call verifySocketManager() for that.
*
* @param pkf absolute path or null
* @return non-null
@@ -400,51 +411,30 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
try {
portNum = Integer.parseInt(tunnel.port);
} catch (NumberFormatException nfe) {
_log.log(Log.CRIT, "Invalid port specified [" + tunnel.port + "], reverting to " + portNum);
throw new IllegalArgumentException("Invalid port specified [" + tunnel.port + "]", nfe);
}
}
I2PSocketManager sockManager = null;
// FIXME: Can't stop a tunnel from the UI while it's in this loop (no session yet)
int retries = 0;
while (sockManager == null) {
FileInputStream fis = null;
try {
if (pkf != null) {
// Persistent client dest
FileInputStream fis = null;
try {
fis = new FileInputStream(pkf);
sockManager = I2PSocketManagerFactory.createManager(fis, tunnel.host, portNum, props);
} catch (IOException ioe) {
if (log != null)
log.log("Error opening key file " + ioe);
_log.error("Error opening key file", ioe);
throw new IllegalArgumentException("Error opening key file " + ioe);
} finally {
if (fis != null)
try { fis.close(); } catch (IOException ioe) {}
}
fis = new FileInputStream(pkf);
sockManager = I2PSocketManagerFactory.createDisconnectedManager(fis, tunnel.host, portNum, props);
} else {
sockManager = I2PSocketManagerFactory.createManager(tunnel.host, portNum, props);
}
if (sockManager == null) {
// try to make this error sensible as it will happen... sadly we can't get to the listenPort, only the listenHost
String msg = "Unable to connect to the router at " + tunnel.host + ':' + portNum +
" and build tunnels for the client";
if (++retries < MAX_RETRIES) {
if (log != null)
log.log(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds");
_log.error(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds");
} else {
if (log != null)
log.log(msg + ", giving up");
_log.log(Log.CRIT, msg + ", giving up");
// not clear if callers can handle null
//return null;
throw new IllegalArgumentException(msg);
}
try { Thread.sleep(RETRY_DELAY); } catch (InterruptedException ie) {}
sockManager = I2PSocketManagerFactory.createDisconnectedManager(null, tunnel.host, portNum, props);
}
} catch (I2PSessionException ise) {
throw new IllegalArgumentException("Can't create socket manager", ise);
} catch (IOException ioe) {
if (log != null)
log.log("Error opening key file " + ioe);
_log.error("Error opening key file", ioe);
throw new IllegalArgumentException("Error opening key file", ioe);
} finally {
if (fis != null)
try { fis.close(); } catch (IOException ioe) {}
}
sockManager.setName("Client");
if (_log.shouldLog(Log.INFO))
@@ -453,6 +443,53 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
return sockManager;
}
/**
* Warning, blocks while connecting to router and building tunnels;
* This may take a LONG time.
*
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
* badly that we cant create a socketManager
* @since 0.9.20
*/
private void connectManager() {
int retries = 0;
while (sockMgr.getSession().isClosed()) {
try {
sockMgr.getSession().connect();
synchronized(I2PTunnelClientBase.class) {
if (sockMgr == socketManager)
_socketManagerState = SocketManagerState.CONNECTED;
}
} catch (I2PSessionException ise) {
// shadows instance _log
Log _log = getTunnel().getContext().logManager().getLog(I2PTunnelClientBase.class);
Logging log = this.l;
// try to make this error sensible as it will happen...
String portNum = getTunnel().port;
if (portNum == null)
portNum = "7654";
String msg;
if (getTunnel().getContext().isRouterContext())
msg = "Unable to connect to the router at " + getTunnel().host + ':' + portNum +
" and build tunnels for the client";
else
msg = "Unable to build tunnels for the client";
if (++retries < MAX_RETRIES) {
if (log != null)
log.log(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds");
_log.error(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds", ise);
} else {
if (log != null)
log.log(msg + ", giving up");
_log.log(Log.CRIT, msg + ", giving up", ise);
throw new IllegalArgumentException(msg, ise);
}
try { Thread.sleep(RETRY_DELAY); } catch (InterruptedException ie) {}
}
}
}
public final int getLocalPort() {
return localPort;
}
@@ -469,11 +506,71 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
/**
* Actually start working on incoming connections. *Must* be
* Actually open the local socket and start working on incoming connections. *Must* be
* called by derived classes after initialization.
*
* (this wasn't actually true until 0.9.20)
*
* This will be fast if i2cp.delayOpen is true, but could take
* a LONG TIME if it is false, as it connects to the router and builds tunnels.
*
* Extending classes must check the value of boolean open after calling
* super.startRunning(), if false then something went wrong.
*
*/
public void startRunning() {
boolean openNow = !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty("i2cp.delayOpen"));
if (openNow) {
while (sockMgr == null) {
verifySocketManager();
if (sockMgr == null) {
_log.error("Unable to connect to router and build tunnels for " + _handlerName);
// FIXME there is a loop in buildSocketManager(), do we really need another one here?
// no matter, buildSocketManager() now throws an IllegalArgumentException
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
} else {
l.log("Tunnels ready for client: " + _handlerName);
}
}
// can't be null unless we limit the loop above
//if (sockMgr == null) {
// l.log("Invalid I2CP configuration");
// throw new IllegalArgumentException("Socket manager could not be created");
//}
} // else delay creating session until createI2PSocket() is called
startup();
}
private void startup() {
if (_log.shouldLog(Log.DEBUG))
_log.debug("startup " + _clientId, new Exception("I did it"));
// prevent JVM exit when running outside the router
boolean isDaemon = getTunnel().getContext().isRouterContext();
open = true;
Thread t = new I2PAppThread(this, "I2PTunnel Client " + getTunnel().listenHost + ':' + localPort, isDaemon);
t.start();
synchronized (this) {
while (!listenerReady && open) {
try {
wait();
} catch (InterruptedException e) {
// ignore
}
}
}
if (open && listenerReady) {
boolean openNow = !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty("i2cp.delayOpen"));
if (openNow || chained)
l.log("Client ready, listening on " + getTunnel().listenHost + ':' + localPort);
else
l.log("Client ready, listening on " + getTunnel().listenHost + ':' + localPort + ", delaying tunnel open until required");
notifyEvent("openBaseClientResult", "ok");
} else {
l.log("Client error for " + getTunnel().listenHost + ':' + localPort + ", check logs");
notifyEvent("openBaseClientResult", "error");
}
synchronized (startLock) {
startRunning = true;
startLock.notify();
@@ -582,18 +679,21 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
/**
* Non-final since 0.9.11.
* Any overrides must set listenerReady = true.
* open will be true before being called.
* Any overrides must set listenerReady = true and then notifyAll() if setup is successful,
* and must call close() and then notifyAll() on failure or termination.
*/
public void run() {
try {
InetAddress addr = getListenHost(l);
if (addr == null) {
open = false;
synchronized (this) {
notifyAll();
}
return;
InetAddress addr = getListenHost(l);
if (addr == null) {
close(true);
open = false;
synchronized (this) {
notifyAll();
}
return;
}
try {
Properties opts = getTunnel().getClientOptions();
boolean useSSL = Boolean.parseBoolean(opts.getProperty(PROP_USE_SSL));
if (useSSL) {
@@ -625,7 +725,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
// Notify constructor that port is ready
synchronized (this) {
listenerReady = true;
notify();
notifyAll();
}
// Wait until we are authorized to process data
@@ -653,14 +753,15 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
manageConnection(s);
}
} catch (IOException ex) {
if (open) {
_log.error("Error listening for connections on " + localPort, ex);
notifyEvent("openBaseClientResult", "error");
}
synchronized (sockLock) {
mySockets.clear();
}
open = false;
if (open) {
_log.error("Error listening for connections on " + addr + " port " + localPort, ex);
l.log("Error listening for connections on " + addr + " port " + localPort + ": " + ex);
notifyEvent("openBaseClientResult", "error");
close(true);
}
synchronized (this) {
notifyAll();
}
@@ -696,13 +797,32 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
* Blocking runner, used during the connection establishment
*/
private class BlockingRunner implements Runnable {
private Socket _s;
private final Socket _s;
public BlockingRunner(Socket s) { _s = s; }
public void run() {
clientConnectionRun(_s);
try {
clientConnectionRun(_s);
} catch (Throwable t) {
// probably an IllegalArgumentException from
// connecting to the router in a delay-open or
// close-on-idle tunnel (in connectManager() above)
_log.error("Uncaught error in i2ptunnel client", t);
}
}
}
/**
* Note that the tunnel can be reopened after this by calling startRunning().
* This may not release all resources. In particular, the I2PSocketManager remains
* and it may have timer threads that continue running.
*
* To release all resources permanently, call destroy().
*
* Does nothing if open is already false.
* Sets open = false but does not notifyAll().
*
* @return success
*/
public boolean close(boolean forced) {
if (_log.shouldLog(Log.INFO))
_log.info("close() called: forced = " + forced + " open = " + open + " sockMgr = " + sockMgr);
@@ -738,8 +858,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
try {
if (ss != null) ss.close();
} catch (IOException ex) {
if (_log.shouldLog(Log.WARN))
_log.warn("error closing", ex);
if (_log.shouldDebug())
_log.debug("error closing", ex);
return false;
}
//l.log("Client closed.");

View File

@@ -63,6 +63,8 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
"HTTP/1.1 405 Bad Method\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"<html><body><H1>I2P ERROR: METHOD NOT ALLOWED</H1>"+
"The request uses a bad protocol. "+
@@ -72,11 +74,16 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
"HTTP/1.1 403 Access Denied\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>"+
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>";
/**
* As of 0.9.20 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
*
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
*/
@@ -85,11 +92,6 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
I2PTunnel tunnel) throws IllegalArgumentException {
super(localPort, ownDest, l, notifyThis, "HTTPS Proxy on " + tunnel.listenHost + ':' + localPort, tunnel);
if (waitEventValue("openBaseClientResult").equals("error")) {
notifyEvent("openConnectClientResult", "error");
return;
}
if (wwwProxy != null) {
StringTokenizer tok = new StringTokenizer(wwwProxy, ", ");
while (tok.hasMoreTokens())
@@ -97,8 +99,6 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
}
setName("HTTPS Proxy on " + tunnel.listenHost + ':' + localPort);
startRunning();
}
/**
@@ -124,7 +124,8 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
@Override
public void startRunning() {
super.startRunning();
_context.portMapper().register(PortMapper.SVC_HTTPS_PROXY, getLocalPort());
if (open)
_context.portMapper().register(PortMapper.SVC_HTTPS_PROXY, getLocalPort());
}
@Override

View File

@@ -30,6 +30,9 @@ public class I2PTunnelHTTPBidirProxy extends I2PTunnelHTTPClient implements Runn
/**
* As of 0.9.20 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
*
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
*/
@@ -38,8 +41,6 @@ public class I2PTunnelHTTPBidirProxy extends I2PTunnelHTTPClient implements Runn
// proxyList = new ArrayList();
setName(getLocalPort() + " -> HTTPClient [NO PROXIES]");
startRunning();
notifyEvent("openHTTPClientResult", "ok");
}
}

View File

@@ -32,7 +32,9 @@ public class I2PTunnelHTTPBidirServer extends I2PTunnelHTTPServer {
bidir = true;
/* start the httpclient */
task = new I2PTunnelHTTPBidirProxy(localPort, l, sockMgr, getTunnel(), getEventDispatcher(), __serverId);
I2PTunnelClientBase client = new I2PTunnelHTTPBidirProxy(localPort, l, sockMgr, getTunnel(), getEventDispatcher(), __serverId);
client.startRunning();
task = client;
sockMgr.setName("Server"); // TO-DO: Need to change this to "Bidir"!
getTunnel().addSession(sockMgr.getSession());
l.log("Ready!");

View File

@@ -91,6 +91,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"HTTP/1.1 403 Access Denied\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>" +
"You attempted to connect to a non-I2P website or location.<BR>";
@@ -112,6 +114,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"HTTP/1.1 503 Service Unavailable\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"<html><body><H1>I2P ERROR: No outproxy found</H1>" +
"Your request was for a site outside of I2P, but you have no " +
@@ -121,6 +125,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"HTTP/1.1 409 Conflict\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"<html><body><H1>I2P ERROR: Destination key conflict</H1>" +
"The addresshelper link you followed specifies a different destination key " +
@@ -136,6 +142,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"HTTP/1.1 404 Not Found\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"<html><body><H1>I2P ERROR: Helper key not resolvable.</H1>" +
"The helper key you put for i2paddresshelper= is not resolvable. " +
@@ -146,6 +154,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"HTTP/1.1 409 New Address\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"<html><body><H1>New Host Name with Address Helper</H1>" +
"The address helper link you followed is for a new host name that is not in your address book. " +
@@ -157,6 +167,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"HTTP/1.1 403 Bad Protocol\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"<html><body><H1>I2P ERROR: NON-HTTP PROTOCOL</H1>" +
"The request uses a bad protocol. " +
@@ -166,6 +178,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"HTTP/1.1 403 Bad URI\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"<html><body><H1>I2P ERROR: INVALID REQUEST URI</H1>" +
"The request URI is invalid, and probably contains illegal characters. " +
@@ -175,6 +189,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"HTTP/1.1 403 Access Denied\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>" +
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>";
@@ -183,6 +199,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"HTTP/1.1 403 SSL Rejected\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"<html><body><H1>I2P ERROR: SSL to I2P address rejected</H1>" +
"SSL for to .i2p addresses denied by configuration." +
@@ -192,6 +210,9 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
* This constructor always starts the tunnel (ignoring the i2cp.delayOpen option).
* It is used to add a client to an existing socket manager.
*
* As of 0.9.20 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
*
* @param sockMgr the existing socket manager
*/
public I2PTunnelHTTPClient(int localPort, Logging l, I2PSocketManager sockMgr, I2PTunnel tunnel, EventDispatcher notifyThis, long clientId) {
@@ -200,12 +221,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
// proxyList = new ArrayList();
setName("HTTP Proxy on " + getTunnel().listenHost + ':' + localPort);
startRunning();
notifyEvent("openHTTPClientResult", "ok");
}
/**
* As of 0.9.20 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
*
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
*/
@@ -216,10 +238,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
_proxyNonce = Long.toString(_context.random().nextLong());
//proxyList = new ArrayList(); // We won't use outside of i2p
if(waitEventValue("openBaseClientResult").equals("error")) {
notifyEvent("openHTTPClientResult", "error");
return;
}
if(wwwProxy != null) {
StringTokenizer tok = new StringTokenizer(wwwProxy, ", ");
@@ -229,9 +247,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
setName("HTTP Proxy on " + tunnel.listenHost + ':' + localPort);
startRunning();
notifyEvent("openHTTPClientResult", "ok");
}
@@ -296,9 +311,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
_context.statManager().createRateStat("i2ptunnel.httpCompressed", "compressed size transferred", "I2PTunnel", new long[] { 60*60*1000 });
_context.statManager().createRateStat("i2ptunnel.httpExpanded", "size transferred after expansion", "I2PTunnel", new long[] { 60*60*1000 });
super.startRunning();
this.isr = new InternalSocketRunner(this);
this.isr.start();
_context.portMapper().register(PortMapper.SVC_HTTP_PROXY, getLocalPort());
if (open) {
this.isr = new InternalSocketRunner(this);
this.isr.start();
int port = getLocalPort();
_context.portMapper().register(PortMapper.SVC_HTTP_PROXY, port);
_context.portMapper().register(PortMapper.SVC_HTTPS_PROXY, port);
}
}
/**
@@ -306,10 +325,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
*/
@Override
public boolean close(boolean forced) {
int port = getLocalPort();
int reg = _context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY);
if(reg == getLocalPort()) {
if (reg == port) {
_context.portMapper().unregister(PortMapper.SVC_HTTP_PROXY);
}
reg = _context.portMapper().getPort(PortMapper.SVC_HTTPS_PROXY);
if (reg == port) {
_context.portMapper().unregister(PortMapper.SVC_HTTPS_PROXY);
}
boolean rv = super.close(forced);
if(this.isr != null) {
this.isr.stopRunning();
@@ -611,6 +635,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
_("i2paddresshelper cannot help you with a destination like that!") +
"</p>").getBytes("UTF-8"));
writeFooter(out);
reader.drain();
// XXX: should closeSocket(s) be in a finally block?
} catch (IOException ioe) {
// ignore
@@ -725,7 +750,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
out.write(getErrorPage("localhost", ERR_LOCALHOST).getBytes("UTF-8"));
writeFooter(out);
reader.drain();
s.close();
} catch (IOException ioe) {
// ignore
} finally {
@@ -1153,6 +1177,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
try {
out.write(("HTTP/1.1 301 Address Helper Accepted\r\n" +
"Location: " + uri + "\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n").getBytes("UTF-8"));
} catch (IOException ioe) {
// ignore
@@ -1378,6 +1404,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
private final static String ERR_HELPER_DISABLED =
"HTTP/1.1 403 Disabled\r\n" +
"Content-Type: text/plain\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"Address helpers disabled";

View File

@@ -63,6 +63,8 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
"HTTP/1.1 407 Proxy Authentication Required\r\n" +
"Content-Type: text/html; charset=UTF-8\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.5\r\n" + // try to get a UTF-8-encoded response back for the password
"Proxy-Authenticate: ";
// put the auth type and realm in between
@@ -78,6 +80,8 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
"HTTP/1.1 503 Service Unavailable\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"<html><body><H1>I2P ERROR: No outproxy found</H1>"+
"Your request was for a site outside of I2P, but you have no "+
@@ -87,6 +91,8 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
"HTTP/1.1 503 Service Unavailable\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n" +
"<html><body><H1>I2P ERROR: DESTINATION NOT FOUND</H1>" +
"That I2P Destination was not found. Perhaps you pasted in the " +

View File

@@ -33,6 +33,9 @@ public class I2PTunnelHTTPClientRunner extends I2PTunnelRunner {
super(s, i2ps, slock, initialI2PData, null, sockList, onFail);
}
/**
* Only call once!
*/
@Override
protected OutputStream getSocketOut() throws IOException {
OutputStream raw = super.getSocketOut();

View File

@@ -71,11 +71,16 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
private static final long TOTAL_HEADER_TIMEOUT = 2 * HEADER_TIMEOUT;
private static final long START_INTERVAL = (60 * 1000) * 3;
private static final int MAX_LINE_LENGTH = 8*1024;
/** ridiculously long, just to prevent OOM DOS @since 0.7.13 */
private static final int MAX_HEADERS = 60;
/** Includes request, just to prevent OOM DOS @since 0.9.20 */
private static final int MAX_TOTAL_HEADER_SIZE = 32*1024;
private long _startedOn = 0L;
private ConnThrottler _postThrottler;
private final static byte[] ERR_UNAVAILABLE =
("HTTP/1.1 503 Service Unavailable\r\n"+
private final static String ERR_UNAVAILABLE =
"HTTP/1.1 503 Service Unavailable\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
@@ -84,11 +89,10 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
"<html><head><title>503 Service Unavailable</title></head>\n"+
"<body><h2>503 Service Unavailable</h2>\n" +
"<p>This I2P website is unavailable. It may be down or undergoing maintenance.</p>\n" +
"</body></html>")
.getBytes();
"</body></html>";
private final static byte[] ERR_DENIED =
("HTTP/1.1 403 Denied\r\n"+
private final static String ERR_DENIED =
"HTTP/1.1 403 Denied\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
@@ -97,11 +101,10 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
"<html><head><title>403 Denied</title></head>\n"+
"<body><h2>403 Denied</h2>\n" +
"<p>Denied due to excessive requests. Please try again later.</p>\n" +
"</body></html>")
.getBytes();
"</body></html>";
private final static byte[] ERR_INPROXY =
("HTTP/1.1 403 Denied\r\n"+
private final static String ERR_INPROXY =
"HTTP/1.1 403 Denied\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
@@ -110,8 +113,64 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
"<html><head><title>403 Denied</title></head>\n"+
"<body><h2>403 Denied</h2>\n" +
"<p>Inproxy access denied. You must run <a href=\"https://geti2p.net/\">I2P</a> to access this site.</p>\n" +
"</body></html>")
.getBytes();
"</body></html>";
private final static String ERR_SSL =
"HTTP/1.1 503 Service Unavailable\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"<html><head><title>503 Service Unavailable</title></head>\n"+
"<body><h2>503 Service Unavailable</h2>\n" +
"<p>This I2P website is not configured for SSL.</p>\n" +
"</body></html>";
private final static String ERR_REQUEST_URI_TOO_LONG =
"HTTP/1.1 414 Request URI too long\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"<html><head><title>414 Request URI Too Long</title></head>\n"+
"<body><h2>414 Request URI too long</h2>\n" +
"</body></html>";
private final static String ERR_HEADERS_TOO_LARGE =
"HTTP/1.1 431 Request header fields too large\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"<html><head><title>431 Request Header Fields Too Large</title></head>\n"+
"<body><h2>431 Request header fields too large</h2>\n" +
"</body></html>";
private final static String ERR_REQUEST_TIMEOUT =
"HTTP/1.1 408 Request timeout\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"<html><head><title>408 Request Timeout</title></head>\n"+
"<body><h2>408 Request timeout</h2>\n" +
"</body></html>";
private final static String ERR_BAD_REQUEST =
"HTTP/1.1 400 Bad Request\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"<html><head><title>400 Bad Request</title></head>\n"+
"<body><h2>400 Bad request</h2>\n" +
"</body></html>";
public I2PTunnelHTTPServer(InetAddress host, int port, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
super(host, port, privData, l, notifyThis, tunnel);
@@ -131,7 +190,6 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
private void setupI2PTunnelHTTPServer(String spoofHost) {
_spoofHost = (spoofHost != null && spoofHost.trim().length() > 0) ? spoofHost.trim() : null;
getTunnel().getContext().statManager().createRateStat("i2ptunnel.httpserver.blockingHandleTime", "how long the blocking handle takes to complete", "I2PTunnel.HTTPServer", new long[] { 60*1000, 10*60*1000, 3*60*60*1000 });
getTunnel().getContext().statManager().createRateStat("i2ptunnel.httpNullWorkaround", "How often an http server works around a streaming lib or i2ptunnel bug", "I2PTunnel.HTTPServer", new long[] { 60*1000, 10*60*1000 });
}
@Override
@@ -208,13 +266,88 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
//local is fast, so synchronously. Does not need that many
//threads.
try {
if (socket.getLocalPort() == 443) {
if (getTunnel().getClientOptions().getProperty("targetForPort.443") == null) {
try {
socket.getOutputStream().write(ERR_SSL.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try {
socket.close();
} catch (IOException ioe) {}
}
return;
}
Socket s = getSocket(socket.getPeerDestination().calculateHash(), 443);
Runnable t = new I2PTunnelRunner(s, socket, slock, null, null,
null, (I2PTunnelRunner.FailCallback) null);
_clientExecutor.execute(t);
return;
}
long afterAccept = getTunnel().getContext().clock().now();
// The headers _should_ be in the first packet, but
// may not be, depending on the client-side options
StringBuilder command = new StringBuilder(128);
Map<String, List<String>> headers = readHeaders(socket, null, command,
CLIENT_SKIPHEADERS, getTunnel().getContext());
Map<String, List<String>> headers;
try {
// catch specific exceptions thrown, to return a good
// error to the client
headers = readHeaders(socket, null, command,
CLIENT_SKIPHEADERS, getTunnel().getContext());
} catch (SocketTimeoutException ste) {
try {
socket.getOutputStream().write(ERR_REQUEST_TIMEOUT.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try { socket.close(); } catch (IOException ioe) {}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new HTTP request", ste);
return;
} catch (EOFException eofe) {
try {
socket.getOutputStream().write(ERR_BAD_REQUEST.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try { socket.close(); } catch (IOException ioe) {}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new HTTP request", eofe);
return;
} catch (LineTooLongException ltle) {
try {
socket.getOutputStream().write(ERR_HEADERS_TOO_LARGE.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try { socket.close(); } catch (IOException ioe) {}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new HTTP request", ltle);
return;
} catch (RequestTooLongException rtle) {
try {
socket.getOutputStream().write(ERR_REQUEST_URI_TOO_LONG.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try { socket.close(); } catch (IOException ioe) {}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new HTTP request", rtle);
return;
} catch (BadRequestException bre) {
try {
socket.getOutputStream().write(ERR_BAD_REQUEST.getBytes("UTF-8"));
} catch (IOException ioe) {
} finally {
try { socket.close(); } catch (IOException ioe) {}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new HTTP request", bre);
return;
}
long afterHeaders = getTunnel().getContext().clock().now();
Properties opts = getTunnel().getClientOptions();
@@ -239,7 +372,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
try {
// Send a 403, so the user doesn't get an HTTP Proxy error message
// and blame his router or the network.
socket.getOutputStream().write(ERR_INPROXY);
socket.getOutputStream().write(ERR_INPROXY.getBytes("UTF-8"));
} catch (IOException ioe) {}
try {
socket.close();
@@ -256,7 +389,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
try {
// Send a 403, so the user doesn't get an HTTP Proxy error message
// and blame his router or the network.
socket.getOutputStream().write(ERR_DENIED);
socket.getOutputStream().write(ERR_DENIED.getBytes("UTF-8"));
} catch (IOException ioe) {}
try {
socket.close();
@@ -341,7 +474,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
try {
// Send a 503, so the user doesn't get an HTTP Proxy error message
// and blame his router or the network.
socket.getOutputStream().write(ERR_UNAVAILABLE);
socket.getOutputStream().write(ERR_UNAVAILABLE.getBytes("UTF-8"));
} catch (IOException ioe) {}
try {
socket.close();
@@ -362,7 +495,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
try {
// Send a 503, so the user doesn't get an HTTP Proxy error message
// and blame his router or the network.
socket.getOutputStream().write(ERR_UNAVAILABLE);
socket.getOutputStream().write(ERR_UNAVAILABLE.getBytes("UTF-8"));
} catch (IOException ioe) {}
try {
socket.close();
@@ -453,7 +586,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
try {
if (browserout == null)
browserout = _browser.getOutputStream();
browserout.write(ERR_UNAVAILABLE);
browserout.write(ERR_UNAVAILABLE.getBytes("UTF-8"));
} catch (IOException ioe) {}
} catch (IOException ioe) {
if (_log.shouldLog(Log.WARN))
@@ -633,9 +766,6 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
return buf.toString();
}
/** ridiculously long, just to prevent OOM DOS @since 0.7.13 */
private static final int MAX_HEADERS = 60;
/**
* Add an entry to the multimap.
*/
@@ -680,13 +810,14 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
* @param socket if null, use in as InputStream
* @param in if null, use socket.getInputStream() as InputStream
* @param command out parameter, first line
* @param command out parameter, first line
* @throws SocketTimeoutException if timeout is reached before newline
* @throws EOFException if EOF is reached before newline
* @throws LineTooLongException if too long
* @throws LineTooLongException if one header too long, or too many headers, or total size too big
* @throws RequestTooLongException if too long
* @throws BadRequestException on bad headers
* @throws IOException on other errors in the underlying stream
*/
private static Map<String, List<String>> readHeaders(I2PSocket socket, InputStream in, StringBuilder command,
static Map<String, List<String>> readHeaders(I2PSocket socket, InputStream in, StringBuilder command,
String[] skipHeaders, I2PAppContext ctx) throws IOException {
HashMap<String, List<String>> headers = new HashMap<String, List<String>>();
StringBuilder buf = new StringBuilder(128);
@@ -694,51 +825,49 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
// slowloris / darkloris
long expire = ctx.clock().now() + TOTAL_HEADER_TIMEOUT;
if (socket != null) {
readLine(socket, command, HEADER_TIMEOUT);
try {
readLine(socket, command, HEADER_TIMEOUT);
} catch (LineTooLongException ltle) {
// convert for first line
throw new RequestTooLongException("Request too long - max " + MAX_LINE_LENGTH);
}
} else {
boolean ok = DataHelper.readLine(in, command);
if (!ok)
throw new IOException("EOF reached before the end of the headers [" + buf.toString() + "]");
throw new EOFException("EOF reached before the end of the headers");
}
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Read the http command [" + command.toString() + "]");
// FIXME we probably don't need or want this in the outgoing direction
int trimmed = 0;
if (command.length() > 0) {
for (int i = 0; i < command.length(); i++) {
if (command.charAt(i) == 0) {
command = command.deleteCharAt(i);
i--;
trimmed++;
}
}
}
if (trimmed > 0)
ctx.statManager().addRateData("i2ptunnel.httpNullWorkaround", trimmed);
int totalSize = command.length();
int i = 0;
while (true) {
if (++i > MAX_HEADERS)
throw new IOException("Too many header lines - max " + MAX_HEADERS);
if (++i > MAX_HEADERS) {
throw new LineTooLongException("Too many header lines - max " + MAX_HEADERS);
}
buf.setLength(0);
if (socket != null) {
readLine(socket, buf, expire - ctx.clock().now());
} else {
boolean ok = DataHelper.readLine(in, buf);
if (!ok)
throw new IOException("EOF reached before the end of the headers [" + buf.toString() + "]");
throw new BadRequestException("EOF reached before the end of the headers");
}
if ( (buf.length() == 0) ||
((buf.charAt(0) == '\n') || (buf.charAt(0) == '\r')) ) {
// end of headers reached
return headers;
} else {
if (ctx.clock().now() >= expire)
throw new IOException("Headers took too long [" + buf.toString() + "]");
if (ctx.clock().now() > expire) {
throw new SocketTimeoutException("Headers took too long");
}
int split = buf.indexOf(":");
if (split <= 0) throw new IOException("Invalid HTTP header, missing colon [" + buf.toString() + "]");
if (split <= 0)
throw new BadRequestException("Invalid HTTP header, missing colon");
totalSize += buf.length();
if (totalSize > MAX_TOTAL_HEADER_SIZE)
throw new LineTooLongException("Req+headers too big");
String name = buf.substring(0, split).trim();
String value = null;
if (buf.length() > split + 1)
@@ -831,5 +960,23 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
super(s);
}
}
/**
* @since 0.9.20
*/
private static class RequestTooLongException extends IOException {
public RequestTooLongException(String s) {
super(s);
}
}
/**
* @since 0.9.20
*/
private static class BadRequestException extends IOException {
public BadRequestException(String s) {
super(s);
}
}
}

View File

@@ -41,6 +41,9 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
public static final String PROP_DCC = "i2ptunnel.ircclient.enableDCC";
/**
* As of 0.9.20 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
*
* @param destinations peers we target, comma- or space-separated. Since 0.9.9, each dest may be appended with :port
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
@@ -81,8 +84,6 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
_dccEnabled = Boolean.parseBoolean(tunnel.getClientOptions().getProperty(PROP_DCC));
// TODO add some prudent tunnel options (or is it too late?)
startRunning();
notifyEvent("openIRCClientResult", "ok");
}
@@ -197,7 +198,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
@Override
public void startRunning() {
super.startRunning();
_context.portMapper().register(PortMapper.SVC_IRC, getLocalPort());
if (open)
_context.portMapper().register(PortMapper.SVC_IRC, getLocalPort());
}
@Override

View File

@@ -99,6 +99,7 @@ public class I2PTunnelOutproxyRunner extends I2PAppThread {
/**
* When was the last data for this runner sent or received?
* As of 0.9.20, returns -1 always!
*
* @return date (ms since the epoch), or -1 if no data has been transferred yet
* @deprecated unused
@@ -107,9 +108,11 @@ public class I2PTunnelOutproxyRunner extends I2PAppThread {
return lastActivityOn;
}
/****
private void updateActivity() {
lastActivityOn = Clock.getInstance().now();
}
****/
/**
* When this runner started up transferring data
@@ -284,26 +287,31 @@ public class I2PTunnelOutproxyRunner extends I2PAppThread {
try {
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
if (_toI2P)
totalSent += len;
else
totalReceived += len;
if (len > 0) updateActivity();
if (len > 0) {
out.write(buffer, 0, len);
if (_toI2P)
totalSent += len;
else
totalReceived += len;
//updateActivity();
}
if (in.available() == 0) {
if (_log.shouldLog(Log.DEBUG))
_log.debug(direction + ": " + len + " bytes flushed through " + (_toI2P ? "to " : "from ")
+ "outproxy");
try {
Thread.sleep(I2PTunnel.PACKET_DELAY);
} catch (InterruptedException e) {
e.printStackTrace();
if (_toI2P) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (in.available() <= 0)
out.flush();
} else {
out.flush();
}
if (in.available() <= 0)
out.flush(); // make sure the data get though
}
}
//out.flush(); // close() flushes

View File

@@ -198,6 +198,7 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr
/**
* When was the last data for this runner sent or received?
* As of 0.9.20, returns -1 always!
*
* @return date (ms since the epoch), or -1 if no data has been transferred yet
* @deprecated unused
@@ -206,9 +207,11 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr
return lastActivityOn;
}
/****
private void updateActivity() {
lastActivityOn = Clock.getInstance().now();
}
****/
/**
* When this runner started up transferring data
@@ -448,28 +451,33 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr
try {
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
if (_toI2P)
totalSent += len;
else
totalReceived += len;
if (len > 0) updateActivity();
if (len > 0) {
out.write(buffer, 0, len);
if (_toI2P)
totalSent += len;
else
totalReceived += len;
//updateActivity();
}
if (in.available() == 0) {
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Flushing after sending " + len + " bytes through");
if (_log.shouldLog(Log.DEBUG))
_log.debug(direction + ": " + len + " bytes flushed through " + (_toI2P ? "to " : "from ")
+ i2ps.getPeerDestination().calculateHash().toBase64().substring(0,6));
try {
Thread.sleep(I2PTunnel.PACKET_DELAY);
} catch (InterruptedException e) {
e.printStackTrace();
+ to);
if (_toI2P) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (in.available() <= 0)
out.flush();
} else {
out.flush();
}
if (in.available() <= 0)
out.flush(); // make sure the data get though
}
}
//out.flush(); // close() flushes

View File

@@ -570,7 +570,11 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
}
public void run() {
blockingHandle(_i2ps);
try {
blockingHandle(_i2ps);
} catch (Throwable t) {
_log.error("Uncaught error in i2ptunnel server", t);
}
}
}

View File

@@ -4,8 +4,9 @@
package net.i2p.i2ptunnel;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
@@ -67,7 +68,7 @@ public class I2Ping extends I2PTunnelClientBase {
// Notify constructor that port is ready
synchronized (this) {
listenerReady = true;
notify();
notifyAll();
}
l.log("*** I2Ping results:");
try {
@@ -157,7 +158,7 @@ public class I2Ping extends I2PTunnelClientBase {
}
if (hostListFile != null) {
BufferedReader br = new BufferedReader(new FileReader(hostListFile));
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(hostListFile), "UTF-8"));
String line;
List<PingHandler> pingHandlers = new ArrayList<PingHandler>();
int i = 0;

View File

@@ -209,7 +209,7 @@ public class TunnelController implements Logging {
if (_state != TunnelState.STOPPED && _state != TunnelState.START_ON_LOAD)
return;
}
new I2PAppThread(new Runnable() { public void run() { startTunnel(); } }).start();
new I2PAppThread(new Runnable() { public void run() { startTunnel(); } }, "Tunnel Starter " + getName()).start();
}
/**
@@ -651,9 +651,9 @@ public class TunnelController implements Logging {
}
// same default logic as in EditBean.getSigType()
if (!isClient(type) ||
((type.equals(TYPE_IRC_CLIENT) || type.equals(TYPE_STD_CLIENT) ||
type.equals(TYPE_SOCKS_IRC) || type.equals(TYPE_STREAMR_CLIENT))
&& !Boolean.valueOf(getSharedClient()))) {
type.equals(TYPE_IRC_CLIENT) || type.equals(TYPE_STD_CLIENT) ||
type.equals(TYPE_SOCKS_IRC) || type.equals(TYPE_STREAMR_CLIENT) ||
(type.equals(TYPE_HTTP_CLIENT) && Boolean.valueOf(getSharedClient()))) {
if (!_config.containsKey(OPT_SIG_TYPE))
_config.setProperty(OPT_SIG_TYPE, PREFERRED_SIGTYPE.name());
}

View File

@@ -45,6 +45,8 @@ public class TunnelControllerGroup implements ClientApp {
private final List<TunnelController> _controllers;
private final ReadWriteLock _controllersLock;
private boolean _controllersLoaded;
private final Object _controllersLoadedLock = new Object();
private final String _configFile;
private static final String REGISTERED_NAME = "i2ptunnel";
@@ -85,7 +87,8 @@ public class TunnelControllerGroup implements ClientApp {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
if (SystemVersion.isAndroid() || !ctx.isRouterContext()) {
_instance = new TunnelControllerGroup(ctx, null, null);
_instance.startup();
if (!SystemVersion.isAndroid())
_instance.startup();
} // else wait for the router to start it
}
return _instance;
@@ -99,6 +102,7 @@ public class TunnelControllerGroup implements ClientApp {
* @param mgr may be null
* @param args one arg, the config file, if not absolute will be relative to the context's config dir,
* if empty or null, the default is i2ptunnel.config
* @throws IllegalArgumentException if too many args
* @since 0.9.4
*/
public TunnelControllerGroup(I2PAppContext context, ClientAppManager mgr, String[] args) {
@@ -146,7 +150,20 @@ public class TunnelControllerGroup implements ClientApp {
* @since 0.9.4
*/
public void startup() {
loadControllers(_configFile);
try {
loadControllers(_configFile);
} catch (IllegalArgumentException iae) {
if (DEFAULT_CONFIG_FILE.equals(_configFile) && !_context.isRouterContext()) {
// for i2ptunnel command line
synchronized (_controllersLoadedLock) {
_controllersLoaded = true;
}
_log.logAlways(Log.WARN, "Not in router context and no preconfigured tunnels");
} else {
throw iae;
}
}
startControllers();
if (_mgr != null)
_mgr.register(this);
// RouterAppManager registers its own shutdown hook
@@ -236,22 +253,28 @@ public class TunnelControllerGroup implements ClientApp {
}
/**
* Load up all of the tunnels configured in the given file (but do not start
* them)
* Load up all of the tunnels configured in the given file.
* Prior to 0.9.20, also started the tunnels.
* As of 0.9.20, does not start the tunnels, you must call startup()
* or getInstance() instead of loadControllers().
*
* DEPRECATED for use outside this class. Use startup() or getInstance().
*
* @throws IllegalArgumentException if unable to load from file
*/
public synchronized void loadControllers(String configFile) {
changeState(STARTING);
synchronized (_controllersLoadedLock) {
if (_controllersLoaded)
return;
}
Properties cfg = loadConfig(configFile);
int i = 0;
_controllersLock.writeLock().lock();
try {
while (true) {
String type = cfg.getProperty("tunnel." + i + ".type");
if (type == null)
if (type == null)
break;
TunnelController controller = new TunnelController(cfg, "tunnel." + i + ".");
_controllers.add(controller);
@@ -260,11 +283,26 @@ public class TunnelControllerGroup implements ClientApp {
} finally {
_controllersLock.writeLock().unlock();
}
synchronized (_controllersLoadedLock) {
_controllersLoaded = true;
}
if (i > 0) {
if (_log.shouldLog(Log.INFO))
_log.info(i + " controllers loaded from " + configFile);
} else {
_log.logAlways(Log.WARN, "No i2ptunnel configurations found in " + configFile);
}
}
/**
* Start all of the tunnels. Must call loadControllers() first.
* @since 0.9.20
*/
private synchronized void startControllers() {
changeState(STARTING);
I2PAppThread startupThread = new I2PAppThread(new StartControllers(), "Startup tunnels");
startupThread.start();
if (_log.shouldLog(Log.INFO))
_log.info(i + " controllers loaded from " + configFile);
changeState(RUNNING);
}
@@ -273,10 +311,14 @@ public class TunnelControllerGroup implements ClientApp {
synchronized(TunnelControllerGroup.this) {
_controllersLock.readLock().lock();
try {
if (_controllers.size() <= 0) {
_log.logAlways(Log.WARN, "No configured tunnels to start");
return;
}
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
if (controller.getStartOnLoad())
controller.startTunnel();
controller.startTunnelBackground();
}
} finally {
_controllersLock.readLock().unlock();
@@ -294,6 +336,7 @@ public class TunnelControllerGroup implements ClientApp {
public synchronized void reloadControllers() {
unloadControllers();
loadControllers(_configFile);
startControllers();
}
/**
@@ -302,6 +345,11 @@ public class TunnelControllerGroup implements ClientApp {
*
*/
public synchronized void unloadControllers() {
synchronized (_controllersLoadedLock) {
if (!_controllersLoaded)
return;
}
_controllersLock.writeLock().lock();
try {
destroyAllControllers();
@@ -309,6 +357,10 @@ public class TunnelControllerGroup implements ClientApp {
} finally {
_controllersLock.writeLock().unlock();
}
synchronized (_controllersLoadedLock) {
_controllersLoaded = false;
}
if (_log.shouldLog(Log.INFO))
_log.info("All controllers stopped and unloaded");
}
@@ -511,11 +563,20 @@ public class TunnelControllerGroup implements ClientApp {
}
/**
* Retrieve a list of tunnels known
* Retrieve a list of tunnels known.
*
* Side effect: if the tunnels have not been loaded from config yet, they
* will be.
*
* @return list of TunnelController objects
* @throws IllegalArgumentException if unable to load config from file
*/
public List<TunnelController> getControllers() {
synchronized (_controllersLoadedLock) {
if (!_controllersLoaded)
loadControllers(_configFile);
}
_controllersLock.readLock().lock();
try {
return new ArrayList<TunnelController>(_controllers);

View File

@@ -109,6 +109,7 @@ public class DCCClientManager extends EventReceiver {
I2PTunnelDCCClient cTunnel = new I2PTunnelDCCClient(b32, localPort, port, l, sockMgr,
_dispatch, _tunnel, ++_id);
cTunnel.attachEventDispatcher(this);
cTunnel.startRunning();
int lport = cTunnel.getLocalPort();
if (_log.shouldLog(Log.WARN))
_log.warn("Opened client tunnel at port " + lport +

View File

@@ -37,6 +37,9 @@ public class I2PTunnelDCCClient extends I2PTunnelClientBase {
public static final String CONNECT_STOP_EVENT = "connectionStopped";
/**
* As of 0.9.20 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
*
* @param dest the target, presumably b32
* @param localPort if 0, use any port, get actual port selected with getLocalPort()
* @throws IllegalArgumentException if the I2PTunnel does not contain
@@ -51,8 +54,6 @@ public class I2PTunnelDCCClient extends I2PTunnelClientBase {
_expires = tunnel.getContext().clock().now() + INBOUND_EXPIRE;
setName("DCC send -> " + dest + ':' + remotePort);
startRunning();
}
/**

View File

@@ -47,8 +47,8 @@ public class IrcInboundFilter implements Runnable {
in = new BufferedReader(new InputStreamReader(remote.getInputStream(), "ISO-8859-1"));
output=local.getOutputStream();
} catch (IOException e) {
if (_log.shouldLog(Log.ERROR))
_log.error("IrcInboundFilter: no streams",e);
if (_log.shouldLog(Log.WARN))
_log.warn("IrcInboundFilter: no streams",e);
return;
}
if (_log.shouldLog(Log.DEBUG))

View File

@@ -47,8 +47,8 @@ public class IrcOutboundFilter implements Runnable {
in = new BufferedReader(new InputStreamReader(local.getInputStream(), "ISO-8859-1"));
output=remote.getOutputStream();
} catch (IOException e) {
if (_log.shouldLog(Log.ERROR))
_log.error("IrcOutboundFilter: no streams",e);
if (_log.shouldLog(Log.WARN))
_log.warn("IrcOutboundFilter: no streams",e);
return;
}
if (_log.shouldLog(Log.DEBUG))

View File

@@ -36,15 +36,28 @@ public abstract class LocalHTTPServer {
private final static String ERR_404 =
"HTTP/1.1 404 Not Found\r\n"+
"Content-Type: text/plain\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"HTTP Proxy local file not found";
private final static String ERR_ADD =
"HTTP/1.1 409 Bad\r\n"+
"Content-Type: text/plain\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"Add to addressbook failed - bad parameters";
private final static String OK =
"HTTP/1.1 200 OK\r\n" +
"Content-Type: text/plain\r\n" +
"Cache-Control: max-age=86400\r\n" +
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"I2P HTTP proxy OK";
/**
* Very simple web server.
*
@@ -72,7 +85,7 @@ public abstract class LocalHTTPServer {
//System.err.println("targetRequest: \"" + targetRequest + "\"");
// a home page message for the curious...
if (targetRequest.equals("/")) {
out.write(("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nCache-Control: max-age=86400\r\n\r\nI2P HTTP proxy OK").getBytes("UTF-8"));
out.write(OK.getBytes("UTF-8"));
out.flush();
return;
}
@@ -103,7 +116,7 @@ public abstract class LocalHTTPServer {
else type = "text/html";
out.write("HTTP/1.1 200 OK\r\nContent-Type: ".getBytes("UTF-8"));
out.write(type.getBytes("UTF-8"));
out.write("\r\nCache-Control: max-age=86400\r\n\r\n".getBytes("UTF-8"));
out.write("\r\nCache-Control: max-age=86400\r\nConnection: close\r\nProxy-Connection: close\r\n\r\n".getBytes("UTF-8"));
FileUtil.readFile(filename, themesDir.getAbsolutePath(), out);
return;
}
@@ -181,6 +194,8 @@ public abstract class LocalHTTPServer {
tbook = book;
out.write(("HTTP/1.1 200 OK\r\n"+
"Content-Type: text/html; charset=UTF-8\r\n"+
"Connection: close\r\n"+
"Proxy-Connection: close\r\n"+
"\r\n"+
"<html><head>"+
"<title>" + _("Redirecting to {0}", host) + "</title>\n" +

View File

@@ -27,25 +27,22 @@ import net.i2p.util.Log;
public class I2PSOCKSTunnel extends I2PTunnelClientBase {
private HashMap<String, List<String>> proxies = null; // port# + "" or "default" -> hostname list
protected Destination outProxyDest = null;
//public I2PSOCKSTunnel(int localPort, Logging l, boolean ownDest) {
// I2PSOCKSTunnel(localPort, l, ownDest, (EventDispatcher)null);
//}
/** @param pkf private key file name or null for transient key */
/**
* As of 0.9.20 this is fast, and does NOT connect the manager to the router,
* or open the local socket. You MUST call startRunning() for that.
*
* @param pkf private key file name or null for transient key
*/
public I2PSOCKSTunnel(int localPort, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel, String pkf) {
super(localPort, ownDest, l, notifyThis, "SOCKS Proxy on " + tunnel.listenHost + ':' + localPort, tunnel, pkf);
if (waitEventValue("openBaseClientResult").equals("error")) {
notifyEvent("openSOCKSTunnelResult", "error");
return;
}
setName("SOCKS Proxy on " + tunnel.listenHost + ':' + localPort);
parseOptions();
startRunning();
notifyEvent("openSOCKSTunnelResult", "ok");
}

View File

@@ -22,6 +22,10 @@ public class MultiSink<S extends Sink> implements Source, Sink {
public void start() {}
/**
* May throw RuntimeException from underlying sinks
* @throws RuntimeException
*/
public void send(Destination from, byte[] data) {
Sink s = this.cache.get(from);
if (s == null) {

View File

@@ -23,6 +23,10 @@ public class ReplyTracker<S extends Sink> implements Source, Sink {
public void start() {}
/**
* May throw RuntimeException from underlying sink
* @throws RuntimeException
*/
public void send(Destination to, byte[] data) {
this.cache.put(to, this.reply);
this.sink.send(to, data);

View File

@@ -24,6 +24,7 @@ import net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketOptions;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
import net.i2p.i2ptunnel.I2PTunnel;
@@ -226,7 +227,7 @@ public class SOCKS5Server extends SOCKSServer {
}
byte addr[] = new byte[addrLen];
in.readFully(addr);
connHostName = new String(addr);
connHostName = DataHelper.getUTF8(addr);
}
_log.debug("DOMAINNAME address type in request: " + connHostName);
break;

View File

@@ -1,6 +1,7 @@
package net.i2p.i2ptunnel.socks;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
/**
@@ -65,7 +66,7 @@ public class SOCKSHeader {
int namelen = (this.header[4] & 0xff);
byte[] nameBytes = new byte[namelen];
System.arraycopy(nameBytes, 0, this.header, 5, namelen);
return new String(nameBytes);
return DataHelper.getUTF8(nameBytes);
}
public Destination getDestination() {

View File

@@ -64,6 +64,10 @@ public class SOCKSUDPPort implements Source, Sink {
this.udpsource.stop();
}
/**
* May throw RuntimeException from underlying sink
* @throws RuntimeException
*/
public void send(Destination from, byte[] data) {
this.wrapper.send(from, data);
}

View File

@@ -30,6 +30,8 @@ public class SOCKSUDPUnwrapper implements Source, Sink {
/**
*
* May throw RuntimeException from underlying sink
* @throws RuntimeException
*/
public void send(Destination ignored_from, byte[] data) {
SOCKSHeader h;

View File

@@ -25,6 +25,8 @@ public class SOCKSUDPWrapper implements Source, Sink {
/**
* Use the cached header, which should have the host string and port
*
* May throw RuntimeException from underlying sink
* @throws RuntimeException
*/
public void send(Destination from, byte[] data) {
if (this.sink == null)

View File

@@ -27,6 +27,10 @@ public class MultiSource implements Source, Sink {
this.sinks.clear();
}
/**
* May throw RuntimeException from underlying sinks
* @throws RuntimeException
*/
public void send(Destination ignored_from, byte[] data) {
for(Destination dest : this.sinks) {
this.sink.send(dest, data);

View File

@@ -1,7 +1,9 @@
package net.i2p.i2ptunnel.streamr;
import net.i2p.i2ptunnel.udp.*;
import net.i2p.I2PAppContext;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
/**
*
@@ -31,7 +33,9 @@ public class Pinger implements Source, Runnable {
// send unsubscribe-message
byte[] data = new byte[1];
data[0] = 1;
this.sink.send(null, data);
try {
this.sink.send(null, data);
} catch (RuntimeException re) {}
}
public void run() {
@@ -41,7 +45,14 @@ public class Pinger implements Source, Runnable {
int i = 0;
while(this.running) {
//System.out.print("p");
this.sink.send(null, data);
try {
this.sink.send(null, data);
} catch (RuntimeException re) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
if (log.shouldWarn())
log.warn("error sending", re);
break;
}
synchronized(this.waitlock) {
int delay = 10000;
if (i < 5) {
@@ -50,7 +61,9 @@ public class Pinger implements Source, Runnable {
}
try {
this.waitlock.wait(delay);
} catch(InterruptedException ie) {}
} catch(InterruptedException ie) {
break;
}
}
}
}

View File

@@ -2,9 +2,11 @@ package net.i2p.i2ptunnel.streamr;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.udp.*;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
/**
* server-mode
@@ -19,10 +21,18 @@ public class Subscriber implements Sink {
this.subscriptions = new ConcurrentHashSet<Destination>();
}
/**
* Doesn't really "send" anywhere, just subscribes or unsubscribes the destination
*
* @param dest to subscribe or unsubscribe
* @param data must be a single byte, 0 to subscribe, 1 to unsubscribe
*/
public void send(Destination dest, byte[] data) {
if(dest == null || data.length < 1) {
// invalid packet
// TODO: write to log
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
if (log.shouldWarn())
log.warn("bad subscription from " + dest);
} else {
byte ctrl = data[0];
if(ctrl == 0) {
@@ -40,7 +50,9 @@ public class Subscriber implements Sink {
multi.remove(dest);
} else {
// invalid packet
// TODO: write to log
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
if (log.shouldWarn())
log.warn("bad subscription from " + dest);
}
}
}

View File

@@ -32,7 +32,10 @@ public class I2PSink implements Sink {
}
}
/** @param src ignored */
/**
* @param src ignored
* @throws RuntimeException if session is closed
*/
public synchronized void send(Destination src, byte[] data) {
//System.out.print("w");
// create payload
@@ -49,9 +52,8 @@ public class I2PSink implements Sink {
this.sess.sendMessage(this.dest, payload,
(this.raw ? I2PSession.PROTO_DATAGRAM_RAW : I2PSession.PROTO_DATAGRAM),
I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED);
} catch(I2PSessionException exc) {
// TODO: handle better
exc.printStackTrace();
} catch (I2PSessionException ise) {
throw new RuntimeException("failed to send data", ise);
}
}

View File

@@ -31,7 +31,10 @@ public class I2PSinkAnywhere implements Sink {
}
}
/** @param to - where it's going */
/**
* @param to - where it's going
* @throws RuntimeException if session is closed
*/
public synchronized void send(Destination to, byte[] data) {
// create payload
byte[] payload;
@@ -47,9 +50,8 @@ public class I2PSinkAnywhere implements Sink {
this.sess.sendMessage(to, payload,
(this.raw ? I2PSession.PROTO_DATAGRAM_RAW : I2PSession.PROTO_DATAGRAM),
I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED);
} catch(I2PSessionException exc) {
// TODO: handle better
exc.printStackTrace();
} catch (I2PSessionException ise) {
throw new RuntimeException("failed to send data", ise);
}
}

View File

@@ -3,10 +3,12 @@ package net.i2p.i2ptunnel.udp;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import net.i2p.I2PAppContext;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionListener;
import net.i2p.client.datagram.I2PDatagramDissector;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
/**
*
@@ -48,7 +50,8 @@ public class I2PSource implements Source, Runnable {
public void run() {
// create dissector
I2PDatagramDissector diss = new I2PDatagramDissector();
while(true) {
_running = true;
while (_running) {
try {
// get id
int id = this.queue.take();
@@ -71,7 +74,10 @@ public class I2PSource implements Source, Runnable {
}
//System.out.print("r");
} catch(Exception e) {
e.printStackTrace();
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
if (log.shouldWarn())
log.warn("error sending", e);
break;
}
}
}
@@ -91,11 +97,15 @@ public class I2PSource implements Source, Runnable {
}
public void disconnected(I2PSession arg0) {
// ignore
_running = false;
thread.interrupt();
}
public void errorOccurred(I2PSession arg0, String arg1, Throwable arg2) {
// ignore
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
log.error(arg1, arg2);
_running = false;
thread.interrupt();
}
}
@@ -106,4 +116,5 @@ public class I2PSource implements Source, Runnable {
protected final Thread thread;
protected final boolean verify;
protected final boolean raw;
private volatile boolean _running;
}

View File

@@ -7,5 +7,9 @@ import net.i2p.data.Destination;
* @author welterde
*/
public interface Sink {
/**
* @param src some implementations may ignore
* @throws RuntimeException in some implementations
*/
public void send(Destination src, byte[] data);
}

View File

@@ -1,5 +1,6 @@
package net.i2p.i2ptunnel.udp;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.InetAddress;
@@ -12,13 +13,15 @@ import net.i2p.data.Destination;
*/
public class UDPSink implements Sink {
/**
* @throws IllegalArgumentException on DatagramSocket IOException
*/
public UDPSink(InetAddress host, int port) {
// create socket
try {
this.sock = new DatagramSocket();
} catch(Exception e) {
// TODO: fail better
throw new RuntimeException("failed to open udp-socket", e);
} catch (IOException e) {
throw new IllegalArgumentException("failed to open udp-socket", e);
}
this.remoteHost = host;
@@ -27,6 +30,10 @@ public class UDPSink implements Sink {
this.remotePort = port;
}
/**
* @param src ignored
* @throws RuntimeException on DatagramSocket IOException
*/
public void send(Destination src, byte[] data) {
// if data.length > this.sock.getSendBufferSize() ...
@@ -36,9 +43,8 @@ public class UDPSink implements Sink {
// send packet
try {
this.sock.send(packet);
} catch(Exception e) {
// TODO: fail a bit better
e.printStackTrace();
} catch (IOException ioe) {
throw new RuntimeException("failed to send data", ioe);
}
}

View File

@@ -1,9 +1,12 @@
package net.i2p.i2ptunnel.udp;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import net.i2p.I2PAppContext;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
/**
*
@@ -12,11 +15,14 @@ import net.i2p.util.I2PAppThread;
public class UDPSource implements Source, Runnable {
public static final int MAX_SIZE = 15360;
/**
* @throws RuntimeException on DatagramSocket IOException
*/
public UDPSource(int port) {
// create udp-socket
try {
this.sock = new DatagramSocket(port);
} catch(Exception e) {
} catch (IOException e) {
throw new RuntimeException("failed to listen...", e);
}
@@ -57,7 +63,9 @@ public class UDPSource implements Source, Runnable {
this.sink.send(null, nbuf);
//System.out.print("i");
} catch(Exception e) {
e.printStackTrace();
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
if (log.shouldWarn())
log.warn("error sending", e);
break;
}
}

View File

@@ -52,8 +52,6 @@ import net.i2p.util.EventDispatcher;
private static final AtomicLong __clientId = new AtomicLong();
protected long _clientId;
protected Destination dest;
private final Object startLock = new Object();
private final I2PSession _session;
@@ -98,6 +96,7 @@ import net.i2p.util.EventDispatcher;
// create a session
try {
ByteArrayInputStream in = new ByteArrayInputStream(key);
// FIXME this may not pick up non-default I2CP host/port settings from tunnel
_session = client.createSession(in, tunnel.getClientOptions());
connected(_session);
} catch(Exception exc) {
@@ -180,6 +179,7 @@ import net.i2p.util.EventDispatcher;
*
* @param to - ignored if configured for a single destination
* (we use the dest specified in the constructor)
* @throws RuntimeException if session is closed
*/
public void send(Destination to, byte[] data) {
_i2pSink.send(to, data);

View File

@@ -87,19 +87,12 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin
private void init(boolean verify, InputStream privData, String privkeyname, Logging l) {
this.l = l;
int portNum = 7654;
if (getTunnel().port != null) {
try {
portNum = Integer.parseInt(getTunnel().port);
} catch (NumberFormatException nfe) {
_log.log(Log.CRIT, "Invalid port specified [" + getTunnel().port + "], reverting to " + portNum);
}
}
// create i2pclient
I2PClient client = I2PClientFactory.createClient();
try {
// FIXME this may not pick up non-default I2CP host/port settings from tunnel
_session = client.createSession(privData, getTunnel().getClientOptions());
connected(_session);
} catch(I2PSessionException exc) {
@@ -195,6 +188,7 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin
* Sink Methods
*
* @param to
* @throws RuntimeException if session is closed
*
*/
public void send(Destination to, byte[] data) {

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