Compare commits

..

657 Commits

Author SHA1 Message Date
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
zzz
dd99978b19 0.9.19 2015-04-12 13:32:49 +00:00
zzz
dd265bbd54 Updates after review:
Remove meeh.i2p as update host (ticket #1515)
Re-add 193.xxx https reseed
Fix SocketManagerFactory property handling
Restore UPnP locale fix lost in the merge
i2ptunnel finals
I2NP unique id fixes
duplicate done() in ReseedChecker
bigger langbox in CSS
reformatting
Javadocs
2015-04-11 19:34:34 +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
kytv
69a0324e86 update debian changelog; bump build 2015-04-09 12:06:26 +00:00
kytv
957d3545b6 Translation updates pulled from Transifex; start of Malagasy translation 2015-04-09 11:59:17 +00:00
kytv
466348a8c5 Updates to geoip.txt and geoipv6.dat.gz based on Maxmind GeoLite Country database from 2015-04-07. 2015-04-09 11:51:55 +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
cce710e377 IRC Server: Better timeout handling when reading initial lines (ticket #723)
Send error responses for timeout, EOF, and bad registration.
Only affects "user" mode, not webirc.
detab
move private fields to top
2015-04-05 17:36:30 +00:00
kytv
013c79bc45 Debian: Refresh patch 2015-04-04 21:59:36 +00:00
dev
1e375886bd merge of '2cb50c2864d750f33039bdbaeb6c15d2bd636ce4'
and 'cb2fbb74aa4412375fdbc546fe2218ca1704cd7d'
2015-04-04 19:49:47 +00:00
dev
d1ac24c65d findbugs: Covariant equals() method defined, Object.equals(Object) inherited 2015-04-04 19:49:37 +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
9d76790cc5 javadoc 2015-04-04 17:01:40 +00:00
zzz
706ee243a5 Streaming read timeout fixes:
i2ptunnel:
- Better timeout handling when reading headers in HTTP server (improved fix for ticket #723)
  Enforce total header timeout with new readLine()
- Prep for returning specific HTTP errors to client on request timeout and header errors,
  instead of just closing socket... further work to be in i2p.i2p.zzz.test2 branch
Streaming:
- Fix read timeout on input stream - was waiting too long, often twice as long as timeout, or more
  Enforce total timeout even when notify()ed
- Fix read() returning 0 on read timeout instead of -1 (possible fix for ticket #335)
  This prevents passing partial headers to server on timeout
- Fix javadocs for read timeout to match current behavior
- Fix StandardSocket SoTimeout to account for differences with I2PSocket readTimeout
- log tweaks
2015-04-04 17:00:57 +00:00
zzz
351a1a8d27 i2ptunnel: Fix NoSuchElementException processing proxyList
caused by 03-31 checkin
2015-04-04 16:59:21 +00:00
zzz
6916cd7977 merge of '18f97452ba9fd5a7274ca689084ffe49b55c2cf3'
and 'c9caed8c48615dc740061fd28315ee659e1afe20'
2015-04-04 15:42:14 +00:00
dev
a444c25c2c silence findbugs: use of uninitialized value 2015-04-04 13:44:37 +00:00
dev
45bc533e38 findbugs fix: equals() used to compare array and nonarray 2015-04-04 13:37:18 +00:00
zzz
03e890b01c merge of '2e3b52a13c62422d86931cd194870b7e2698f3c2'
and 'fde331f6b10f0ef936a2aa0d68092df22348a581'
2015-04-04 11:21:50 +00:00
dev
0c90162e20 Copy directly into buffer without intermediate buffer 2015-04-04 02:27:24 +00:00
dev
ddc3ef8db3 Removed unnecessry buffering 2015-04-04 00:05:29 +00:00
zzz
fcec43b7ca i2ptunnel: Fix stopping tunnel on bad args when starting,
broken by new state code
2015-04-03 23:46:24 +00:00
zzz
edb614d970 wrapper.config: Remove old mortbay properties, unused by new Jetty 2015-04-03 23:40:39 +00:00
dev
820b99e3d3 Commented out java runtime argument 2015-04-03 23:20:39 +00:00
dev
cf0453cee0 Initialize uniqueId lazily to avoid wasting entropy for messages where it isn't used 2015-04-03 23:01:16 +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
dev
b7b5512e7a Formatting 2015-04-02 23:01: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
dev
bb68728c82 Added link to blog post explaining why the flag was added 2015-04-02 20:44:52 +00:00
dev
f3b2eb69d2 Fixed syntax error 2015-04-02 16:32:38 +00:00
dev
168d688fc9 Disable JVM stats being written to file, to prevent long (up to ~400ms) pauses.
- Blog post: http://www.evanjones.ca/jvm-mmap-pause.html
    - This change prevents tools that use the stats-file (/tmp/hsperfdata) from working (like jstat)
2015-04-02 16:05:43 +00:00
dev
ade93ea76d Added model name for Xeon E3-1230v2 2015-04-02 15:58:46 +00:00
dg2-new
44503af88b * Job Queue/stats: add stat/graph for amount of scheduled jobs. 2015-04-01 22:34:39 +00:00
zzz
eb7693561b spelling 2015-04-01 13:59:51 +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
2ef615a3f7 I2CP: Allow larger client clock skew (ticket #1503),
better error message to client
javadocs
2015-04-01 12:50:51 +00:00
zzz
20197fc3ec i2psnark: Fix changing data directory on Windows (ticket #1503) 2015-04-01 12:41:38 +00:00
zzz
fadc624f7c API: Fix some client-side APIs to honor defaults in Properties;
add javadocs to specify where we do and don't (ticket #1491)
2015-03-31 13:18:11 +00:00
zzz
22c4149358 fix another split() bug 2015-03-31 11:26:02 +00:00
zzz
c770c6bc6a i2ptunnel: Fix multiple SSL outproxies in HTTP client
escape and truncate URL on error page
2015-03-31 11:21:32 +00:00
zzz
891408191e UPnP: Don't rescan when shutting down 2015-03-29 14:59:11 +00:00
zzz
9a8fa246a9 I2CP: Prevent NPE when router receives messages without prior session (ticket #1503) 2015-03-29 13:45:14 +00:00
zzz
83c3152b5d JobQueue: Don't start thread in constructor (ticket #973) 2015-03-29 13:40:04 +00:00
zzz
956730c5e9 log tweak to help diagnose ServerSocket closed 2015-03-28 10:54:00 +00:00
zzz
72b9c92a6e better 7 bit error message 2015-03-28 10:51:59 +00:00
zzz
349255d252 exit code checks and javadocs 2015-03-28 10:49:43 +00:00
zzz
ac902badcd log tweak to hide i2pd badness 2015-03-28 10:47:10 +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
f3d573cab0 i2ptunnel HTTP client: Replace all getBytes() calls
with a Writer or getBytes("UTF-8") for efficiency and to
avoid encoding issues.
Store strings as strings, not bytes.
Catch IOEs to prevent cascading error pages.
Minor cleanups
2015-03-25 12:10:14 +00:00
zzz
9e18c7ea18 Streaming: Throw I2PSocketException when connection is reset,
display new error page in HTTP client (ticket #643)
javadocs
2015-03-24 14:33:36 +00:00
zzz
a975dc4427 Summary bar: linkify news headings, remove 'show news' link 2015-03-23 15:47:33 +00:00
zzz
b875e284af merge of '33b368d75d4b7536dd4a29efa35fba64e6dc409d'
and '8eb5a0d367c4b34eadc326e0ba727e998e6f5505'
2015-03-23 14:21:05 +00:00
str4d
46fe4298b9 States for TunnelController (#815) 2015-03-23 13:59:05 +00:00
str4d
9790d3ba64 Tweak so TODO is marked in IDEs 2015-03-23 12:50:33 +00:00
str4d
2d31f30a22 ReadWriteLock in TunnelControlGroup (#815) 2015-03-23 12:49:30 +00:00
str4d
2fefe93922 merge of '91e8b79f2d8c4ffd26867eb6ddd0ee63d22b0ca9'
and 'dd39c6a48fec46017ce527d8b8b8208369ecda5e'
2015-03-23 12:47:40 +00:00
str4d
399b068a4e Fixed NPE in test 2015-03-23 03:54:21 +00:00
zzz
dcffde6eeb Javadoc: missing package.html files in applications (ticket #1109) 2015-03-22 18:37:40 +00:00
zzz
78074f6a7e Javadoc: missing package.html files in i2p.jar (ticket #1109) 2015-03-22 17:32:35 +00:00
zzz
79dc01f7e4 Javadoc: missing package.html files in router.jar (ticket #1109) 2015-03-22 16:35:21 +00:00
zzz
0f6040ecb1 enforce a minimum number of RIs to bundle 2015-03-22 12:44:32 +00:00
zzz
a0ab72e362 more /configreseed help text 2015-03-22 12:26:05 +00:00
zzz
2c45378c6d Console: Better status feedback on manual reseed from URL
Reseed: Better status feedback and cleanup in summary bar
2015-03-22 10:08:48 +00:00
zzz
44c75187f5 set tunnel name for ping 2015-03-22 08:30:38 +00:00
zzz
2609a4d124 Floodfill: Don't become ff w/o ECDSA support
Don't transition to non-ff when shutting down if configured true
Set ff for cap P and X
2015-03-22 08:30:10 +00:00
zzz
2d58501db3 Plugins: Add form to browse for local plugin file to install,
easy since we have multipart in console now
Better status feedback from update manager to console
2015-03-21 17:23:19 +00:00
zzz
a337185820 better temp dir fallback and logging 2015-03-21 12:38:48 +00:00
zzz
9c0aa0c271 randomize i2psnark temp dir name 2015-03-21 12:19:03 +00:00
zzz
b2e908f094 add removed certs to delete list 2015-03-21 12:14:07 +00:00
zzz
ef32d37073 TunnelPool: Reduce expl. quantity adder for ff since we're
doing mostly direct lookups now, and delay adding them at
startup to give client tunnels a chance
2015-03-21 12:13:22 +00:00
zzz
f0961a9658 more accurate job stats 2015-03-21 12:10:10 +00:00
str4d
876b5714be merge of '7c32d2fbb882e6d56cb06fc0e272f05ee2c0b8ed'
and '7e72459b27feb5176e98c5efc843f63e46e8f63d'
2015-03-21 09:59:00 +00:00
str4d
825cd7ff4c Docstring spelling fix 2015-03-21 04:29:45 +00:00
str4d
47f3476078 More I2PTunnel UI logic into GeneralHelper 2015-03-21 04:29:32 +00:00
kytv
7b10ebc117 fix previous commit 2015-03-20 19:43:01 +00:00
kytv
e5cdfd206d Re-enable uk.reseed.i2p2.no; it's back up (ticket #1487) 2015-03-20 19:25:42 +00:00
zzz
dd4c62b560 TunnelDispatcher: Start part. tunnel cleanup job sooner since
we're accepting tunnels sooner.
2015-03-20 16:54:03 +00:00
zzz
aae801efaf sort config tabs 2015-03-20 16:51:34 +00:00
zzz
e02d44433d missed file from last checkin 2015-03-20 13:32:42 +00:00
zzz
590a3c98e5 charset 2015-03-20 12:32:53 +00:00
zzz
7f472e4ee9 Console:
- Move multipart form support from susimail to jetty-i2p.jar
    so console can use it
  - Add multipart form support to formhandler.jsi and FormHandler.java
Reseed:
  - Fix zip magic number
  - Finish manual reseed from local file
package.html files for jetty-i2p.jar
2015-03-20 12:30:04 +00:00
zzz
a3802d4d8b javadoc fix 2015-03-20 12:29:40 +00:00
zzz
59348f8dbd Reseed:
- Add form to manually reseed from zip or su3 URL
    (result status not yet working)
  - Add form to manually reseed from local zip or su3 file
    (not yet working, needs multipart/form-date moved from susimail)
  - Add form to create reseed zip file to share
    (working)
  - Backend support and refactoring in reseed code
2015-03-19 23:17:18 +00:00
zzz
8742a66f2f fix susimail HTTP headers 2015-03-19 21:36:23 +00:00
zzz
a2f027e136 NetDB: Don't publish non-ff RI on exit if we are coming right back 2015-03-18 19:58:31 +00:00
zzz
cb4359cd0a Streaming: Reduce min RTT again 2015-03-18 17:50:40 +00:00
zzz
163c172823 StatisticsManager: Publish dummy LS count if we just started 2015-03-18 17:29:08 +00:00
zzz
80a2d2c1f5 Router: Allow disabling the setting of some System properties, for embedded applications 2015-03-18 14:40:17 +00:00
zzz
486f282999 add CoreVersion.getVersion() 2015-03-18 14:13:05 +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
zzz
91fe62eee3 History for prop, -6:
Prop from i2p.i2p.zzz.upnp, containing:
Cyberlink for Java v3.0 + (2015-02-15) from github
See branch revs for more info and fixups.
Previous was Cyberlink for Java v2.1 (2011-09-16) from SVN.
From a scan of the 2.1-to-3.0 diff, it's mostly
formatting changes, getting rid of DOS line endings,
and a couple of new features we don't need.
I see very few fixes. And the Device.getAbsoluteURL()
"fixes" did not work in my testing, I had to fix them again.
Unlikely to fix any of the open UPnP tickets #481 #725 #728 #1194 #1480.
But now we're current.
2015-03-18 12:15:41 +00:00
zzz
d3f5596cb2 propagate from branch 'i2p.i2p.zzz.upnp' (head 8719ae9a1473d748947733043f465a4589cc23d5)
to branch 'i2p.i2p' (head 5ae9785903c4b9452f4241758e8ddc1338e94574)
2015-03-18 12:13:41 +00:00
zzz
d7a88db87a NetDB:
- Send exploratory lookups directly to the floodfill if
    we are already connected to him
  - Don't encrypt RI lookups when overloaded
  - Don't explore when overloaded
  - SearchJob cleanups
Tunnels: Drop instead of reject requests on high job lag
2015-03-18 12:10:30 +00:00
zzz
0af1f67c33 Router: Revert deprecation;
addCapabilities() tweaks
2015-03-17 21:38:59 +00:00
zzz
8dde7b70db UPnP:
- New fix Device.getAbsoluteURL() once again after merge
 - Don't load local files in Service.getSCPDNode()
2015-03-17 21:29:03 +00:00
zzz
64faeef6c4 restore previous javadoc fixes after merge 2015-03-17 19:11:21 +00:00
zzz
c79e4aeaea propagate from branch 'i2p.i2p' (head 97716ce246bcbee153cf1a28253bac2385ddf7be)
to branch 'i2p.i2p.zzz.upnp' (head e508f71db90f382080b98d11efbdb4d88c1bc406)
2015-03-17 18:49:37 +00:00
zzz
8b6a86e391 merge of 'c5e201203713f0fefcdef642ca50597f8936c79c'
and 'fbd68f812db1e891f96e212b3a5938beec0233b5'
2015-03-17 18:21:12 +00:00
zzz
92daf4a8df Cyberlink for Java v3.0 + (2015-02-15) from github:
Unmodified cybergarage-upnp from github rev 9499b03 2015-02-05
https://github.com/cybergarage/cybergarage-upnp/commits/master
which is the same as rev 3ed1af9 2014-07-28 except for
the addition of README.md which we aren't using.
This is post-version 3.0.

Omitted files:
  router/java/src/org/cybergarage/xml/parser/XercesParser.java
  router/java/src/org/cybergarage/xml/parser/XmlPullParser.java
  router/java/src/org/cybergarage/xml/parser/kXML2Parser.java
chmod all files back to 644.

Diverging from 2.1 checkin rev 59eae97dbb470d8c4a1e4dba3a9763e134bb0c53
in prep for merging.

License unchanged.
Compile tested only.
2015-03-17 14:36:05 +00:00
zzz
819b07a52a minor refactor 2015-03-17 13:18:30 +00:00
zzz
b8f8c6129d prevent negative sleep 2015-03-17 13:17:38 +00:00
zzz
25d1ae195a New translations from tx:
Indonesian, Finnish, Malagasy, Albanian, Korean, Ukrainian, Brazilian Portuguese, Dutch
Note broken translations in TX config file
2015-03-17 13:16:40 +00:00
zzz
d22b05e114 NetDB: Send RI lookups directly to the floodfill if
we are already connected to him
(from ISJ only; does not affect exploration, verifies, LSes, ...)
2015-03-16 22:40:25 +00:00
zzz
db25eff74a log tweak 2015-03-16 22:38:29 +00:00
zzz
c927441d66 case-insensitive sort of stats 2015-03-16 20:14:32 +00:00
zzz
7e4832d5f2 lint 2015-03-16 15:44:45 +00:00
zzz
819b35c760 Router: Increase exploratory tunnel quantity if floodfill 2015-03-16 15:20:03 +00:00
zzz
071498c413 Router: Republish RI early if capabilities change
- RI javadoc clarifications WRT caps
2015-03-16 15:10:36 +00:00
zzz
7125ed0492 Apache Tomcat 6.0.43 2015-03-16 09:34:37 +00:00
zzz
de201bdd9c Throttle: Reject tunnels based on job lag 2015-03-16 09:12:41 +00:00
zzz
4fccd258e6 javadoc fixes 2015-03-16 09:08:03 +00:00
str4d
56d705739b Migrate accessors to GeneralHelper, fix broken outproxyAuth boolean 2015-03-15 20:26:36 +00:00
str4d
2a9d61b1ed merge of '6eb0d9bd5731afaa33fa1a0c82dd08a1d16d104b'
and 'f4fa275a1d6e014c64c5ff063fb890dd05e4ed60'
2015-03-15 20:13:16 +00:00
zzz
a9f6839a04 NetDb: Track flood success 2015-03-15 13:37:22 +00:00
zzz
5b555855ef Clear displayed tracker issues when restarting torrent
lint
2015-03-15 12:52:26 +00:00
zzz
76cf80a3d0 Job Queue:
- Fix overload dropping
   - Add drop count to job stats
   - Decrease overload threshold again
   - Concurrent tweaks
2015-03-15 11:48:12 +00:00
zzz
4c6aaa32b6 Router javadocs, stub out class P,
throw ISE instead of exit() if another router running
2015-03-15 11:42:00 +00:00
zzz
74ab1bff53 threshold tweaks for floodfill 2015-03-15 11:37:03 +00:00
zzz
b5bba5e3c8 log tweak 2015-03-15 11:35:49 +00:00
str4d
7e5bd17714 Move saveTunnel() and deleteTunnel() from IndexBean into i2ptunnel-ui.jar 2015-03-14 02:52:16 +00:00
zzz
ec6207fc78 Job Queue:
- Drop garlic message decryption jobs on overload
  - Decrease overload threshold
2015-03-13 17:50:32 +00:00
zzz
36d47a0ba9 minor cleanup 2015-03-13 17:48:29 +00:00
zzz
0289cefd8d lint 2015-03-13 17:26:15 +00:00
dg2-new
521eb2d8f8 Router: create router.integratedPeers (floodfills) stat, and allow graphing of it. 2015-03-13 16:53:08 +00:00
zzz
0494266649 i2psnark:
- Auto-reduce tunnel quantity based on peer count
  - Increase max tunnels
2015-03-13 14:56:35 +00:00
zzz
8fac5c064e fix i2ptunnel.war 2015-03-13 14:14:49 +00:00
str4d
0b6f74e646 Enable proxy authentication type to be configured 2015-03-11 23:46:38 +00:00
str4d
b8b272a5b8 Better multi-mode setters 2015-03-11 10:57:07 +00:00
str4d
a570e09166 Explicit boolean setters in TunnelConfig 2015-03-11 10:34:02 +00:00
str4d
1919e36c30 Move TunnelConfig to .ui, separate it from i2ptunnel.jar 2015-03-11 03:58:24 +00:00
str4d
812c00f11e Move TunnelController config creation logic into class that Android UI can use 2015-03-10 20:05:45 +00:00
kytv
419e27cfd1 Disable (jp|uk).reseeder.i2p2.no (tickets #1422, #1487) 2015-03-09 15:49:52 +00:00
kytv
d761c02909 Remove commented out reseed server i2p-netdb.innovatio.no and its associated certificates. 2015-03-09 15:40:40 +00:00
zzz
c7d1d2b69a console: Hide cancel graceful shutdown button unless we are shutting down 2015-03-08 20:23:00 +00:00
zzz
0972b6b56a more test cases 2015-03-08 20:20:50 +00:00
zzz
6e3cf7869f log tweak 2015-03-08 20:20:06 +00:00
zzz
f7337b4891 i2psnark: Increase min and default bandwidth
Add creation date to created torrents
log tweaks
more test cases
2015-03-08 20:19:12 +00:00
zzz
55161dec17 Router Throttle: Tweak messages during probabalistic rejection,
other cleanup
2015-03-08 20:07:05 +00:00
zzz
b65b53b0df Transport: Add missing bogons to IP validity check
192.0.0.2 seen out there (RFC 6333)
2015-03-08 20:05:50 +00:00
zzz
49e1e1c8a4 minor transport cleanup 2015-03-08 20:02:28 +00:00
str4d
9b73fcda40 Include priority for logged strings 2015-03-04 19:07:28 +00:00
str4d
b92e1ee9aa Split LogWriter to make Android subsititution simpler 2015-03-02 10:56:50 +00:00
kytv
04ac54cd35 Re-enabling host; its su3 files are now properly signed. 2015-03-01 23:37:27 +00:00
kytv
d47916f753 re-enable jp.reseed.i2p2.no (ticket #1422) 2015-03-01 22:34:15 +00:00
zzz
b0ea1d691a log fix, comment fix 2015-02-23 09:50:43 +00:00
zzz
ce041dfbc1 0.9.18 2015-02-22 09:52:27 +00:00
zzz
4613da093d log level tweak, bump for review 2015-02-19 09:47:44 +00:00
kytv
2d5f7aaae5 year typo fix 2015-02-18 23:48:21 +00:00
kytv
5a7a7ac83d typo fix 2015-02-18 22:36:52 +00:00
kytv
f217af2deb extend checkcerts.sh to print bits and hash information 2015-02-18 22:36:33 +00:00
kytv
6d58f9a354 Updates to geoip.txt and geoipv6.dat.gz based on Maxmind GeoLite Country database from 2014-02-04. 2015-02-18 22:34:09 +00:00
kytv
29953ea5e4 Debian: confine daemon with apparmor (ticket #1061) 2015-02-18 22:25:24 +00:00
kytv
bb9cef1e40 Add example apparmor profile (ticket #1092) 2015-02-18 21:38:25 +00:00
kytv
ece2f1484c refresh debian patch 2015-02-18 21:32:34 +00:00
kytv
a3c8a4363d Pulling in translations from Transifex 2015-02-18 20:20:52 +00:00
kytv
2f90b5a201 refresh debian patch 2015-02-17 19:27:11 +00:00
dg2-new
d4bbdc28f3 FloodfillMonitorJob: use the 60 min rate avg instead of lifetime avg, but fallback to the lifetime.
SAMStreamSend: fix tabbing from earlier commit.
2015-02-16 17:27:17 +00:00
dg2-new
f41df969b7 merge of '3e2231827648f614c5df325d9904e8d454e9a847'
and 'cddd2e9d2cf6f5c50a7d9948fbb2b3247d9768eb'
2015-02-16 08:07:54 +00:00
dg2-new
f87d006a1c FloodfillMonitorJob:
- Use lifetime average value for job lag
 - Change the job lag limit to less than 25ms
 - Consider and set the limit of backlogged tunnels to less than 5
2015-02-15 22:40:36 +00:00
kytv
f4fa9a7d8f New cert for i2p.mooo.com. Will be switched on the server in a future release. 2015-02-15 19:16:07 +00:00
kytv
c52047e6cd Remove reseed host by hoster's request 2015-02-15 19:10:48 +00:00
dg2-new
9163d41228 * I2PSnark, Jetty, SAM, crypto: findbugs resource leaks. 2015-02-10 21:57:27 +00:00
kytv
1be9bb29e8 disabling us.i2p2.no over http 2015-02-08 15:05:04 +00:00
kytv
522a89a045 reseed: remove reseed.info; hoster is discontinuing the service. 2015-02-08 15:00:01 +00:00
zzz
06b9b6a7fb more clock log tweaks 2015-02-08 12:52:51 +00:00
zzz
7f9c565cd7 fix early NPE 2015-02-08 00:42:43 +00:00
zzz
201afc823e SSU: Limit range for valid clock skew
Reduce log level for ignored clock adjustment
2015-02-07 14:13:14 +00:00
zzz
f4c79c885a Transport: Ban routers if they are too old and we are non-DSA 2015-02-07 14:03:42 +00:00
zzz
656202c9db debug tweak 2015-02-07 14:01:56 +00:00
zzz
72b64072d5 missed file for event log change 2015-02-07 13:59:11 +00:00
zzz
b72271f9a4 NTCP: Block IP for a while when incoming connection is dropped before
receiving a message. Possible workaround for tickets #551, #1075, #1411.
Root cause of problem not yet found.
- Increase threshold for loop throttle, this probably isn't the problem.
- Log tweaks
2015-02-06 15:09:45 +00:00
zzz
b0d09d28f4 SSU: Change peer test log error to warn.
This is caused by an i2pd bug, already fixed.
2015-02-06 11:18:20 +00:00
zzz
b9197e35b5 NetDB: Reduce max job lag for floodfill, was far too high 2015-02-06 00:51:32 +00:00
zzz
e431be2cbe NTCP minor cleanups, javadocs, atomics 2015-02-06 00:49:21 +00:00
zzz
761c883c1f Add event log for reachability change 2015-02-06 00:47:41 +00:00
zzz
60f86f342b Decrease DH refiller initial delay and increase buffer size
to reduce chance of running out on high-bandwidth routers
2015-02-06 00:46:13 +00:00
zzz
1234b6b148 stat tweak 2015-02-06 00:45:24 +00:00
str4d
6f45242fc8 Plugin SU3 cert for str4d@mail.i2p 2015-02-04 23:03:42 +00:00
zzz
36c45ccb7b Console: Show UPnP status even if disabled (ticket #1459) 2015-02-04 16:11:17 +00:00
zzz
90cf71b5bc rename headers after review 2015-02-04 11:54:18 +00:00
zzz
7165dc7860 NetDB: Don't flood an RI back to itself. While Java ffs self-flood,
other implementations may not.
2015-02-01 19:57:18 +00:00
zzz
5491287931 OCMOSJ: Pick a OB tunnel at random, not with the OBEP closest
to the lease, as that may be reducing the odds of trying a
different path and hurting connection reliability.
While the change may slightly increase connection congestion,
if it helps with reliability then it's worth it.
2015-02-01 19:53:11 +00:00
zzz
7256096b8a Router: Call warmupCrypto() earlier in the initialization, so it
actually happens before some other thread needs the crypto
2015-02-01 19:49:25 +00:00
zzz
b6008b5414 Crypto: Catch IAE in generateCertificate() 2015-02-01 19:47:09 +00:00
zzz
1042d21278 log tweak 2015-02-01 14:07:56 +00:00
zzz
47eff7ee86 PRNG: Don't hang forever at startup waiting for SecureRandom init 2015-01-31 17:37:59 +00:00
zzz
3da850a6b9 bump -17 2015-01-31 15:20:37 +00:00
zzz
a1358deda2 private method 2015-01-31 15:16:42 +00:00
zzz
df0bbfd615 Netdb: Encrypt lookups for 32-bit x86 also 2015-01-31 15:13:52 +00:00
zzz
0568ac3aa5 javadoc 2015-01-31 15:13:04 +00:00
zzz
e63a69170e Transport: set 4 MBps max bw due to bloom filter 2015-01-31 15:12:21 +00:00
zzz
711f8dedd9 console: disable changing log path 2015-01-31 15:10:45 +00:00
zzz
09c3737a94 reduce log level 2015-01-31 12:53:49 +00:00
zzz
9384424173 disable floodfill in laptop mode 2015-01-31 00:12:25 +00:00
zzz
4936f08212 Console: Don't display invalid IPv6 addresses as options on /confignet 2015-01-30 17:26:45 +00:00
zzz
03f4ebbe35 add throttle stat 2015-01-30 16:17:39 +00:00
zzz
0671785ab2 NTCP: Throttle event pumper if looping too fast (tickets #551, #1075, #1411)
This is just a simple workaround, root cause unknown.
May need tuning.
2015-01-30 16:00:45 +00:00
zzz
381dbc4b4a Proxy error page tweaks 2015-01-30 15:55:12 +00:00
zzz
84cf531f5f SSU: Fix transition from firewalled to non-firewalled 2015-01-29 22:23:28 +00:00
zzz
175806115b SSU:
- Sort introducers in router address, so we won't force a republish
due to a different ordering of the same introducers
- Don't publish an address if we need introducers but don't have any,
so the user won't see a 'firewalled with inbound NTCP enabled' message
2015-01-29 20:34:49 +00:00
zzz
86b45ab1e5 SSU: Fix replaceExternalAddress churn when firewalled,
caused by change in 0.9.17 removing IP/port from published address
when firewalled. We must now keep a local unpublished address
also, containing the detected IP/port.
2015-01-29 15:53:04 +00:00
zzz
17939036bc move comparators to their own class 2015-01-29 12:52:46 +00:00
zzz
5bf515441e Router: Ensure nonzero tunnel IDs 2015-01-28 21:43:27 +00:00
zzz
06edb9f2a6 Router: Stub out capabilities P and X (ticket #1447) 2015-01-28 18:07:45 +00:00
zzz
33b58f5fab UPnP:
- Callback when device removed
  - Consolidate callbacks
  - Clear ignored devices after primary device removed
    to allow one to be promoted on rescan
2015-01-28 17:38:52 +00:00
zzz
47a012a4dd initialize blocklist sooner 2015-01-28 17:36:53 +00:00
zzz
e5801be43e only use valid IP for geoIP 2015-01-28 16:25:50 +00:00
zzz
d5a6ac591c more UPnP locking fixes 2015-01-28 16:25:08 +00:00
zzz
59373f9bdf UPnP:
- Rescan for devices periodically and when reachability changes (tickets #661, #959)
  - Don't put "I2P" in registered protocol name
  - Add uptime to UPnP info
  - HTML escaping
  - Remove static log on Android
  - Javadocs and cleanups
2015-01-28 15:04:59 +00:00
zzz
5da492b9e5 spelling 2015-01-19 12:44:31 +00:00
zzz
9bcc951f10 i2psnark: Skip incompatible welterde tracker if we are ECDSA 2015-01-11 18:21:45 +00:00
zzz
3270ba840e I2PTunnel: Add option for multihoming optimization 2015-01-11 17:36:39 +00:00
zzz
45b3e44cc2 NetDB: Stubs for bandwidth estimation during reseed (ticket #935)
Incomplete and may not ever be, for evaluation only.
2015-01-10 16:51:13 +00:00
zzz
7ed855b2d2 NetDB: Publish RI faster when costs change (ticket #1437)
PLRIJ interval was 37-50 minutes. Reduce that by 4x,
but for 3 out of 4 times, only publish if something changes,
including cost. 4th time, always publish, as before.
This will hopefully reduce routers getting slammed to
conn limits on a transport.
2015-01-09 17:03:33 +00:00
zzz
f08552c2d1 javadocs 2015-01-09 16:58:57 +00:00
zzz
9a4c19b24b reduce log level 2015-01-08 19:32:42 +00:00
zzz
690b695373 remove jisko.i2p, down since 2014-11-08 2015-01-08 18:21:11 +00:00
zzz
65348b2365 more renaming 2015-01-08 18:20:08 +00:00
zzz
285c13d900 fix reseed checking at startup, broken in previous checkin 2015-01-07 23:15:10 +00:00
zzz
0a938d9048 Router: Don't reset uptime after a soft restart
Tunnels: Temporarily increase exploratory tunnel quantity at startup,
so that netdb refresh will work better
2015-01-07 20:11:04 +00:00
zzz
a02a265802 trim all xml news data 2015-01-07 19:55:37 +00:00
zzz
eeeeef81cf NetDB: Possible fixes for reseed completion not recognized (ticket #1384) 2015-01-07 19:16:55 +00:00
zzz
bcb9fe5f24 Startup: Accept tunnels after 10 minutes instead of 20 (ticket #1152) 2015-01-07 19:14:44 +00:00
zzz
37f34d83f8 Router: Add startup/shutdown state machine
Tunnels: Cleanup, catch more cases of zero-hop configuration
ClientAppConfig: Start i2ptunnel sooner
  Since BuildRequestor won't use a zero-hop exploratory as a paired tunnel
  for client builds, it's now safe to start client tunnels
  before the expl. tunnels are ready. This will save up to 90 seconds.
2015-01-07 17:54:21 +00:00
zzz
b3238079c3 reorder 2015-01-06 14:39:14 +00:00
zzz
ee1edb3383 renaming 2015-01-06 14:10:25 +00:00
zzz
7767430af2 EepGet: Fix PcapWriter 2015-01-05 17:05:36 +00:00
zzz
2e5185aa99 EepGet: Change command line default to 0 retries 2015-01-05 15:22:32 +00:00
zzz
6e847a4cc4 Streaming: Add API for sending/receiving payload in ping/pong 2015-01-05 15:09:12 +00:00
zzz
045f6dccf8 Latency reduction all over:
- SSU: Reduce ack delay
- Streaming: Reduce min RTO and flusher delay
- Tunnels: Reduce GW batching time
2015-01-05 13:19:34 +00:00
zzz
d7895a456a minor optimization 2015-01-05 13:17:59 +00:00
zzz
7753d05b61 UrlLauncher:
- Configure browser with routerconsole.browser (ticket #1159)
- Convert to ClientApp interface
2015-01-05 12:42:39 +00:00
zzz
043b4776c3 move port under interface in form 2015-01-05 12:40:46 +00:00
zzz
5db764de5f Blocklist:
- Rewrite to read and merge multiple files
- Include in update, use version in base dir too
- Increase limits
- Bug fixes
2015-01-05 12:38:38 +00:00
zzz
3ae846a713 m4b mime type 2015-01-03 14:15:48 +00:00
zzz
927e29b8ef I2PTunnel: Persist leaseset keys
I2CP: Use configured leaseset keys if available
2015-01-03 13:32:24 +00:00
meeh
d271411552 Added Dock fix for Mac OSX 10.10 2015-01-03 01:51:32 +00:00
kytv
31d98ac4a5 new reseed host 2014-12-30 02:18:30 +00:00
kytv
78f4cc8e30 Add two certs to deletelist (missed in last commit) 2014-12-22 16:27:58 +00:00
kytv
cce30a8f42 reseed changes
- cowpuncher is moving to rows.io
- (temporarily) disabling 193.150.* due to downtime
- removing unnecessary certs
2014-12-21 20:41:34 +00:00
zzz
a9e928fb46 Eepsite help: Removed statements requiring dest to end in AAAA.
Translations updated also, but may need some further fixup.
2014-12-19 14:14:04 +00:00
zzz
60017f7c55 Crypto: Stubs for encryption key types 2014-12-17 14:41:24 +00:00
zzz
eb46f74e24 I2CP: Don't log full session config on error 2014-12-17 14:30:11 +00:00
kytv
5e890bd781 checkremotecerts.sh: torify was recently deprecated and now is just an alias pointing to
torsocks, so let's use torsocks directly
2014-12-15 15:18:19 +00:00
zzz
20facf78d0 bump -3 2014-12-15 14:51:34 +00:00
zzz
96db43cc8e unchoke new peer faster 2014-12-15 14:43:37 +00:00
zzz
ab4f209c10 remove xml stats link 2014-12-15 14:40:38 +00:00
zzz
fa51a0aef4 enhance logging for inproxy rejections 2014-12-15 14:40:00 +00:00
zzz
aa6a5e053c raise max concurrent tunnel builds 2014-12-15 14:38:33 +00:00
zzz
03df6c2ba0 less casting 2014-12-15 14:38:07 +00:00
kytv
501f645e60 disabling reseed host i2p-netdb.innovatio.no: unresponsive hoster + config issues.
Could be re-enabled when/if problems are fixed.
2014-12-14 23:32:11 +00:00
zzz
23534b31c6 SU3File: Infer SigType from private key when signing,
Change default to RSA 4096
SigUtil: Add conversion methods for Java keys with unknown types
2014-12-14 17:52:23 +00:00
zzz
d35363cdbc SU3File: Fix getContentOffset(); fail on excess data after sig 2014-12-14 15:52:44 +00:00
zzz
ba34c90b7f EdDSA cleanup, another null resource check 2014-12-13 20:56:49 +00:00
kytv
94a19171ed reseed server and comment updates 2014-12-13 18:54:28 +00:00
kytv
8099591589 correct certificate line endings 2014-12-13 18:38:41 +00:00
kytv
df6bbc59b3 update of reseed ssl certificates:
The webpack* and cloudflare* certificates are for ssl.webpack.de and
cowpuncher.drollette.com, respectively.  I'm removing the smartcom.org
certificate because it's unused.
2014-12-13 18:29:12 +00:00
zzz
05a616aa0d SU3File: Implement 'extract -k' 2014-12-11 20:58:04 +00:00
zzz
c84105e783 add cacert cert to deletelist 2014-12-10 17:57:16 +00:00
zzz
262721cc90 SSU: reduce log level of uncaught errors processing I2NP message 2014-12-10 17:56:37 +00:00
kytv
c24168d5cd remove unused and weak md5 certficate 2014-12-10 14:39:44 +00:00
zzz
4e529a68d3 Console: Prevent two-word translations from splitting across lines in summary bar 2014-12-09 15:16:41 +00:00
kytv
4f3244e93b add new, stronger certificate for netdb.i2p2.no
The old certificate will not be replaced on the server yet.  The old cert is
SHA/1024-bit. New cert is SHA256/2048-bit key.
2014-12-08 23:50:06 +00:00
zzz
b2e17916e4 HTTP Proxy: Fix parsing of ECDSA address helper,
ignore '=' when comparing, reindent test
2014-12-08 14:12:00 +00:00
zzz
57ac344e7f show infohash in upper case 2014-12-08 14:08:45 +00:00
zzz
98e275d908 javadoc typo 2014-12-08 14:05:35 +00:00
zzz
8420b6c715 NetDB: Increase lookup throttle time 2014-12-08 14:05:08 +00:00
kytv
3dfcb2d5cc (temporarily?) disable jp.reseed.i2p2.no (ticket #1422), add a note that netdb.i2p2.no is currently v3 only 2014-12-07 15:42:57 +00:00
zzz
540720a912 unit test fixes 2014-12-05 16:18:25 +00:00
zzz
f86200e3ae history for prop, -1 2014-12-05 15:37:01 +00:00
zzz
9e43618028 Plugins: More thread group debugging for isRunning check;
Don't count Jetty RolloverFileOutputStream in the thread group,
to fix restart of a plugin
2014-12-05 15:35:38 +00:00
zzz
aacdba1bc7 KeyGenerator: main() test improvements
Allow specification of sig types on command line
2014-12-05 15:32:34 +00:00
zzz
c28d060d52 Update: Use last-modified instead of last-checked for the next
if-modified-since fetch, to fix failing to fetch the latest news
2014-12-05 15:30:53 +00:00
zzz
bf3fdbb1ab Increase default class O conn. limits to 350 NTCP, 1050 SSU 2014-12-05 15:27:24 +00:00
zzz
0a7a637d46 javadocs 2014-12-05 15:21:45 +00:00
zzz
e842165265 more argument checking, javadocs 2014-12-05 15:21:26 +00:00
zzz
2db82da910 cleanup 2014-12-05 15:19:26 +00:00
zzz
9953bc3024 javadoc 2014-12-05 15:18:24 +00:00
zzz
2ba4992d88 propagate from branch 'i2p.i2p.zzz.test2' (head 0feb2e6806927f68c7333aaa0892de185bb2629c)
to branch 'i2p.i2p' (head 0482fa843cb1e9d7ec281440056eef3a0ab07bdb)
2014-12-05 15:14:40 +00:00
zzz
5e67008d26 I2PTunnel: Reduce i2ptunnel threads, more thread pooling.
Big savings is on client side (two less threads per connection)
 - Move client pool from static inI2PTunnelClientBase to TCG.
 - Use client pool for some server threads
 - Run some things inline that were formerly threads
 - Client-side I2PTunnelRunner thread used to do nothing but start 2 more
   threads; now it runs one inline (like we do for server-side HTTP)
 - Javadocs and cleanups
Was originally intended to reduce load for high-traffic servers
but most of the savings for now is on the client side.
Ref: http://zzz.i2p/topics/1741
Todo: Figure out how to run the HTTP client-side gunzipper inline too
Todo: More server-side improvements

---

Client side:

before:
4-5 threads, 1-2 pooled

  I2PTunnel Client Runner (BlockingRunner from client pool)
      starts I2PTunnelRunner or I2PTunnelHTTPClientRunner and exits
          starts StreamForwarder toI2P and waits
          starts StreamForwarder fromI2P and waits
              starts HTTPResponseOutputStream (HTTP gunzip only) (from client pool)
now:
2-3 threads, 1-2 pooled

  I2PTunnel Client Runner (BlockingRunner from client pool)
      runs I2PTunnelRunner or I2PTunnelHTTPClientRunner inline
          starts StreamForwarder toI2P and waits
          runs StreamForwarder fromI2P inline
              starts HTTPResponseOutputStream (HTTP gunzip only) (from client pool)

---

Server side:

before:
1-4 threads, 0-1 pooled

  Server Handler Pool (Handler from server pool) execpt for standard server, blockingHandle() inline in acceptor
      starts I2PTunnelRunner or CompressedRequestor and exits
          starts StreamForwarder toI2P and waits   (inline for HTTP)
          starts StreamForwarder fromI2P and waits  (except not for HTTP GET)

now:
1-4 threads, 0-2 pooled

  Server Handler Pool (Handler from server pool) execpt for standard server, blockingHandle() inline in acceptor
      starts I2PTunnelRunner or CompressedRequestor and exits (using client pool)
          starts StreamForwarder toI2P and waits   (inline for HTTP)
          starts StreamForwarder fromI2P and waits  (except not for HTTP GET)
2014-12-05 15:12:51 +00:00
zzz
e7b50c5940 reduce auto-stop threshold again 2014-12-02 15:23:50 +00:00
zzz
78d7277298 show b32 for local leasesets too 2014-12-02 15:11:12 +00:00
zzz
fb641187b8 use new getVersion() 2014-12-02 13:42:58 +00:00
zzz
4b2715c36f RouterInfo: Add convenience method getVersion() 2014-12-02 13:30:31 +00:00
zzz
f1e9f5d4fd DatabaseStoreMessage: Mask the unused bits in the type field,
in case we ever want to use them for options
2014-12-02 13:28:48 +00:00
zzz
2d43d349ab add more invalid ports 2014-12-02 13:22:26 +00:00
zzz
1773fc0e0d Add more clues to file locations in default config files 2014-11-28 14:23:34 +00:00
zzz
6d6f7fb89b Data: Disallow duplicate keys in a Mapping 2014-11-28 13:45:33 +00:00
zzz
449ce3176e propagate from branch 'i2p.i2p' (head b4b595d294ace07f7fde583957d8e00e96af347c)
to branch 'i2p.i2p.zzz.test2' (head 90c482d231ea639bff8d37d390dac081e361f48f)
2014-11-28 13:13:00 +00:00
zzz
5383f9f097 Profiles: Change slice selection argument from an int to an enum for clarity 2014-11-25 14:25:42 +00:00
zzz
a16d17c422 SusiMail: Add save-as button
Fix encoding for filename in Content-Disposition header
New icon from Silk, same license as the others
2014-11-24 18:36:16 +00:00
zzz
31cc0764a9 Logger: Configurable flush interval 2014-11-18 14:49:23 +00:00
zzz
8f8adfa39e propagate from branch 'i2p.i2p' (head bde4ef3680071b416b3528bad4c16245964f432a)
to branch 'i2p.i2p.zzz.test2' (head 183d2a30edd10165451d0cbbf75636f3b1dfda16)
2014-11-15 17:48:39 +00:00
zzz
5044f3e58f I2NP:
Move some data structures away from ByteArray; offsets were always zero
  - New BuildRequestRecord constructors
  - BuildRequestRecord field becomes final byte[222]
  - IV becomes byte[16]
  - Build record becomes EncryptedBuildRecord
Remove extra copy in BuildRequestRecord.encryptRecord()
Remove unused BuildRequestRecord.readOurIdentityMatches()
2014-11-15 17:48:11 +00:00
1027 changed files with 124108 additions and 91564 deletions

View File

@@ -33,6 +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
;; 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
@@ -81,11 +83,15 @@ source_lang = en
trans.ar = apps/routerconsole/locale-news/messages_ar.po
trans.de = apps/routerconsole/locale-news/messages_de.po
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
;; 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
trans.mg = apps/routerconsole/locale-news/messages_mg.po
trans.nb = apps/routerconsole/locale-news/messages_nb.po
trans.nl = apps/routerconsole/locale-news/messages_nl.po
trans.pl = apps/routerconsole/locale-news/messages_pl.po
@@ -94,6 +100,7 @@ trans.pt_BR = apps/routerconsole/locale-news/messages_pt_BR.po
trans.ro = apps/routerconsole/locale-news/messages_ro.po
trans.ru_RU = apps/routerconsole/locale-news/messages_ru.po
trans.sk = apps/routerconsole/locale-news/messages_sk.po
trans.sq = apps/routerconsole/locale-news/messages_sq.po
trans.sv_SE = apps/routerconsole/locale-news/messages_sv.po
trans.tr_TR = apps/routerconsole/locale-news/messages_tr.po
trans.uk_UA = apps/routerconsole/locale-news/messages_uk.po
@@ -114,6 +121,7 @@ trans.fr = apps/routerconsole/locale-countries/messages_fr.po
trans.hu = apps/routerconsole/locale-countries/messages_hu.po
trans.it = apps/routerconsole/locale-countries/messages_it.po
trans.ja = apps/routerconsole/locale-countries/messages_ja.po
trans.mg = apps/routerconsole/locale-countries/messages_mg.po
trans.nb = apps/routerconsole/locale-countries/messages_nb.po
trans.nl = apps/routerconsole/locale-countries/messages_nl.po
trans.pl = apps/routerconsole/locale-countries/messages_pl.po
@@ -208,17 +216,22 @@ trans.cs = apps/susimail/locale/messages_cs.po
trans.da = apps/susimail/locale/messages_da.po
trans.de = apps/susimail/locale/messages_de.po
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
;; 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
trans.nl = apps/susimail/locale/messages_nl.po
trans.ru_RU = apps/susimail/locale/messages_ru.po
trans.sv_SE = apps/susimail/locale/messages_sv.po
trans.pl = apps/susimail/locale/messages_pl.po
trans.pt = apps/susimail/locale/messages_pt.po
trans.pt_BR = apps/susimail/locale/messages_pt_BR.po
trans.ro = apps/susimail/locale/messages_ro.po
trans.ru_RU = apps/susimail/locale/messages_ru.po
trans.sq = apps/susimail/locale/messages_sq.po
trans.sv_SE = apps/susimail/locale/messages_sv.po
trans.uk_UA = apps/susimail/locale/messages_uk.po
trans.vi = apps/susimail/locale/messages_vi.po
trans.zh_CN = apps/susimail/locale/messages_zh.po
@@ -230,16 +243,21 @@ trans.cs = debian/po/cs.po
trans.de = debian/po/de.po
trans.el = debian/po/el.po
trans.es = debian/po/es.po
trans.fi = debian/po/fi.po
trans.fr = debian/po/fr.po
trans.id = debian/po/id.po
trans.it = debian/po/it.po
trans.hu = debian/po/hu.po
trans.ja = debian/po/ja.po
trans.ko = debian/po/ko.po
trans.nl = debian/po/nl.po
trans.pl = debian/po/pl.po
trans.pt = debian/po/pt.po
trans.pt_BR = debian/po/pt_BR.po
trans.ro = debian/po/ro.po
trans.ru_RU = debian/po/ru.po
trans.sk = debian/po/sk.po
trans.sq = debian/po/sq.po
trans.sv_SE = debian/po/sv.po
trans.uk_UA = debian/po/uk.po
trans.tr_TR = debian/po/tr.po
@@ -248,12 +266,20 @@ trans.zh_CN = debian/po/zh.po
[I2P.i2prouter-script]
source_file = installer/resources/locale/po/messages_en.po
source_lang = en
;; currently fails check
;;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
trans.pl = installer/resources/locale/po/messages_pl.po
trans.ja = installer/resources/locale/po/messages_ja.po
;; currently fails check
;;trans.ko = installer/resources/locale/po/messages_ko.po
trans.nl = installer/resources/locale/po/messages_nl.po
trans.pl = installer/resources/locale/po/messages_pl.po
trans.pt = installer/resources/locale/po/messages_pt.po
trans.pt_BR = installer/resources/locale/po/messages_pt_BR.po
@@ -262,6 +288,8 @@ trans.ru_RU = installer/resources/locale/po/messages_ru.po
trans.sk = installer/resources/locale/po/messages_sk.po
trans.sv_SE = installer/resources/locale/po/messages_sv.po
trans.tr_TR = installer/resources/locale/po/messages_tr.po
;; currently fails check
;;trans.uk_UA = installer/resources/locale/po/messages_uk.po
trans.zh_CN = installer/resources/locale/po/messages_zh.po
[I2P.getopt]
@@ -271,28 +299,44 @@ 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
;; 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
trans.nl = core/java/src/gnu/getopt/MessagesBundle_nl.properties
trans.nb = core/java/src/gnu/getopt/MessagesBundle_nb.properties
trans.pl = core/java/src/gnu/getopt/MessagesBundle_pl.properties
trans.pt_BR = core/java/src/gnu/getopt/MessagesBundle_pt_BR.properties
;; currently corrupt, non-UTF-8
;;trans.pt = core/java/src/gnu/getopt/MessagesBundle_pt.properties
;; currently corrupt, non-UTF-8
;;trans.pt_BR = core/java/src/gnu/getopt/MessagesBundle_pt_BR.properties
trans.ro = core/java/src/gnu/getopt/MessagesBundle_ro.properties
trans.ru_RU = core/java/src/gnu/getopt/MessagesBundle_ru.properties
trans.sk = core/java/src/gnu/getopt/MessagesBundle_sk.properties
;; currently corrupt, non-UTF-8
;;trans.sq = core/java/src/gnu/getopt/MessagesBundle_sq.properties
trans.uk_UA = core/java/src/gnu/getopt/MessagesBundle_uk.properties
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
;; 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.41:
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

@@ -54,11 +54,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

@@ -0,0 +1,11 @@
<html>
<body>
<p>
The addressbook application, which fetches hosts.txt files from subscription URLS via
HTTP and adds new hosts to the local database.
While implemented as a webapp, this application contains no user interface.
May also be packaged as a jar, as is done for Android.
The webapp named 'addressbook' in the console is actually SusiDNS.
</p>
</body>
</html>

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

@@ -0,0 +1,99 @@
# Last Modified: Sun Apr 12 22:08:32 2015
# vim:syntax=apparmor et ts=8 sw=4
#include <tunables/global>
$INSTALL_PATH/{i2prouter,runplain.sh} flags=(complain) {
#include <abstractions/base>
#include <abstractions/fonts>
#include <abstractions/nameservice>
#include <abstractions/ssl_certs>
capability sys_ptrace,
network inet stream,
network inet6 stream,
$INSTALL_PATH/ r,
$INSTALL_PATH/{i2psvc,wrapper} rmix,
owner $INSTALL_PATH/** rwklm,
# Needed for Java
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,
/usr/share/javazi/** r,
# Debian
/etc/java-{6,7,8}-openjdk/** r,
/usr/lib/jvm/default-java/jre/bin/java rix,
# Debian, Ubuntu, openSUSE
/usr/lib{,32,64}/jvm/java-*-openjdk-*/jre/bin/java rix,
/usr/lib{,32,64}/jvm/java-*-openjdk-*/jre/bin/keytool rix,
# Raspbian
/usr/lib/jvm/jdk-*-oracle-*/jre/bin/java rix,
/usr/lib/jvm/jdk-*-oracle-*/jre/bin/keytool rix,
# Fonts are needed for I2P's graphs
/usr/share/java/java-atk-wrapper.jar r,
# Used by some plugins
/usr/share/java/eclipse-ecj-*.jar r,
/{,var/}tmp/ rwm,
owner /{,var/}tmp/** rwklm,
/{,usr/}bin/{,b,d}ash rix,
/{,usr/}bin/cat rix,
/{,usr/}bin/cut rix,
/{,usr/}bin/dirname rix,
/{,usr/}bin/expr rix,
/{,usr/}bin/{,g,m}awk rix,
/{,usr/}bin/grep rix,
/{,usr/}bin/id rix,
/{,usr/}bin/ldd rix,
/{,usr/}bin/ls rix,
/{,usr/}bin/mkdir rix,
/{,usr/}bin/nohup rix,
/{,usr/}bin/ps rix,
/{,usr/}bin/rm rix,
/{,usr/}bin/sed rix,
/{,usr/}bin/sleep rix,
/{,usr/}bin/tail rix,
/{,usr/}bin/tr rix,
/{,usr/}bin/uname rix,
/{,usr/}bin/which rix,
@{HOME}/.java/fonts/** r,
owner @{HOME}/.i2p/ rw,
owner @{HOME}/.i2p/** rwk,
# Prevent spamming the logs
deny owner @{HOME}/.java/ wk,
deny @{HOME}/.fontconfig/ wk,
deny @{HOME}/.java/fonts/** w,
deny /dev/tty rw,
deny /dev/pts/[0-9]* rw,
deny @{PROC}/[0-9]*/fd/ r,
deny /usr/local/share/fonts/ r,
deny /var/cache/fontconfig/ wk,
# Used by some versions of the Tanuki wrapper but never used by I2P
deny /usr/share/java/hamcrest*.jar r,
deny /usr/share/java/junit*.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

@@ -3,20 +3,22 @@
# This file is distributed under the same license as the desktopgui package.
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# <b790979@klzlk.com>, 2011.
# Translators:
# PolishAnon <b790979@klzlk.com>, 2011
# polacco <polacco@i2pmail.org>, 2015
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: https://trac.i2p2.de/\n"
"POT-Creation-Date: 2011-03-03 18:29+0000\n"
"PO-Revision-Date: 2011-05-25 18:36+0000\n"
"Last-Translator: PolishAnon <b790979@klzlk.com>\n"
"Language-Team: Polish (http://www.transifex.net/projects/p/I2P/team/pl/)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-01-09 19:27+0000\n"
"PO-Revision-Date: 2015-02-17 20:54+0000\n"
"Last-Translator: polacco <polacco@i2pmail.org>\n"
"Language-Team: Polish (http://www.transifex.com/projects/p/I2P/language/pl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: pl\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:23
msgid "Start I2P"
@@ -32,7 +34,7 @@ msgstr "Uruchamianie"
#: src/net/i2p/desktopgui/InternalTrayManager.java:26
msgid "Launch I2P Browser"
msgstr "Uruchom Przeglądarke I2P"
msgstr "Uruchom przeglądarkę I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:50
msgid "Configure desktopgui"
@@ -46,12 +48,10 @@ msgstr "Zrestartuj I2P"
msgid "Stop I2P"
msgstr "Zatrzymaj I2P"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:44
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:43
msgid "Tray icon configuration"
msgstr "Konfiguracja ikony zasobnika"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:47
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:46
msgid "Should tray icon be enabled?"
msgstr "Czy ikona zasobnika powinna być aktywna?"

View File

@@ -6,13 +6,14 @@
# Translators:
# Denis Blank <gribua@gmail.com>, 2011
# LinuxChata, 2014
# madjong <madjong@i2pmail.org>, 2014
msgid ""
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-06-22 10:20+0000\n"
"Last-Translator: LinuxChata\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"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -50,7 +51,7 @@ msgstr "Зупинити I2P"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:43
msgid "Tray icon configuration"
msgstr "Настройка трей-іконки"
msgstr "Налаштування трей-іконки"
#: src/net/i2p/desktopgui/gui/DesktopguiConfigurationFrame.java:46
msgid "Should tray icon be enabled?"

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,16 @@ public class BitField
}
}
/**
* 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

@@ -74,7 +74,6 @@ public class I2PSnarkUtil {
private static final int EEPGET_CONNECT_TIMEOUT_SHORT = 5*1000;
public static final int DEFAULT_STARTUP_DELAY = 3;
public static final boolean DEFAULT_USE_OPENTRACKERS = true;
public static final int DEFAULT_MAX_UP_BW = 8; //KBps
public static final int MAX_CONNECTIONS = 16; // per torrent
public static final String PROP_MAX_BW = "i2cp.outboundBytesPerSecond";
public static final boolean DEFAULT_USE_DHT = true;
@@ -97,7 +96,7 @@ public class I2PSnarkUtil {
setI2CPConfig("127.0.0.1", 7654, null);
_banlist = new ConcurrentHashSet<Hash>();
_maxUploaders = Snark.MAX_TOTAL_UPLOADERS;
_maxUpBW = DEFAULT_MAX_UP_BW;
_maxUpBW = SnarkManager.DEFAULT_MAX_UP_BW;
_maxConnections = MAX_CONNECTIONS;
_startupDelay = DEFAULT_STARTUP_DELAY;
_shouldUseOT = DEFAULT_USE_OPENTRACKERS;
@@ -106,8 +105,8 @@ public class I2PSnarkUtil {
// This is used for both announce replies and .torrent file downloads,
// so it must be available even if not connected to I2CP.
// so much for multiple instances
_tmpDir = new SecureDirectory(ctx.getTempDir(), baseName);
FileUtil.rmdir(_tmpDir, false);
_tmpDir = new SecureDirectory(ctx.getTempDir(), baseName + '-' + ctx.random().nextInt());
//FileUtil.rmdir(_tmpDir, false);
_tmpDir.mkdirs();
}
@@ -329,7 +328,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;
@@ -457,7 +456,7 @@ public class I2PSnarkUtil {
return null;
}
String getOurIPString() {
public String getOurIPString() {
Destination dest = getMyDestination();
if (dest != null)
return dest.toBase64();

View File

@@ -29,6 +29,9 @@ class IdleChecker extends SimpleTimer2.TimedEvent {
private int _consec;
private int _consecNotRunning;
private boolean _isIdle;
private String _lastIn = "3";
private String _lastOut = "3";
private final Object _lock = new Object();
private static final long CHECK_TIME = 63*1000;
private static final int MAX_CONSEC_IDLE = 4;
@@ -46,16 +49,19 @@ class IdleChecker extends SimpleTimer2.TimedEvent {
}
public void timeReached() {
synchronized (_lock) {
locked_timeReached();
}
}
private void locked_timeReached() {
if (_util.connected()) {
boolean torrentRunning = false;
boolean hasPeers = false;
int peerCount = 0;
for (PeerCoordinator pc : _pcs) {
if (!pc.halted()) {
torrentRunning = true;
if (pc.getPeers() > 0) {
hasPeers = true;
break;
}
peerCount += pc.getPeers();
}
}
@@ -73,19 +79,22 @@ class IdleChecker extends SimpleTimer2.TimedEvent {
}
}
if (hasPeers) {
if (_isIdle)
restoreTunnels();
if (peerCount > 0) {
restoreTunnels(peerCount);
} else {
if (!_isIdle) {
if (_consec++ >= MAX_CONSEC_IDLE)
reduceTunnels();
else
restoreTunnels(1); // pretend we have one peer for now
}
}
} else {
_isIdle = false;
_consec = 0;
_consecNotRunning = 0;
_lastIn = "3";
_lastOut = "3";
}
schedule(CHECK_TIME);
}
@@ -101,12 +110,13 @@ class IdleChecker extends SimpleTimer2.TimedEvent {
}
/**
* Restore tunnel count
* Restore or adjust tunnel count based on current peer count
* @param peerCount greater than zero
*/
private void restoreTunnels() {
_isIdle = false;
if (_log.shouldLog(Log.INFO))
private void restoreTunnels(int peerCount) {
if (_isIdle && _log.shouldLog(Log.INFO))
_log.info("Restoring tunnels on activity");
_isIdle = false;
Map<String, String> opts = _util.getI2CPOptions();
String i = opts.get("inbound.quantity");
if (i == null)
@@ -120,7 +130,30 @@ class IdleChecker extends SimpleTimer2.TimedEvent {
String ob= opts.get("outbound.backupQuantity");
if (ob == null)
ob = "0";
setTunnels(i, o, ib, ob);
// we don't need more tunnels than we have peers, reduce if so
// reduce to max(peerCount / 2, 2)
int in, out;
try {
in = Integer.parseInt(i);
} catch (NumberFormatException nfe) {
in = 3;
}
try {
out = Integer.parseInt(o);
} catch (NumberFormatException nfe) {
out = 3;
}
int target = Math.max(peerCount / 2, 2);
if (target < in && in > 2) {
in = target;
i = Integer.toString(in);
}
if (target < out && out > 2) {
out = target;
o = Integer.toString(out);
}
if (!(_lastIn.equals(i) && _lastOut.equals(o)))
setTunnels(i, o, ib, ob);
}
/**
@@ -132,12 +165,16 @@ class IdleChecker extends SimpleTimer2.TimedEvent {
if (mgr != null) {
I2PSession sess = mgr.getSession();
if (sess != null) {
if (_log.shouldLog(Log.INFO))
_log.info("New tunnel settings " + i + " / " + o + " / " + ib + " / " + ob);
Properties newProps = new Properties();
newProps.setProperty("inbound.quantity", i);
newProps.setProperty("outbound.quantity", o);
newProps.setProperty("inbound.backupQuantity", ib);
newProps.setProperty("outbound.backupQuantity", ob);
sess.updateOptions(newProps);
_lastIn = i;
_lastOut = o;
}
}
}

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

@@ -92,7 +92,7 @@ public class MetaInfo
this.announce_list = announce_list;
this.comment = null;
this.created_by = null;
this.creation_date = 0;
this.creation_date = I2PAppContext.getGlobalContext().clock().now();
// TODO if we add a parameter for other keys
//if (other != null) {
@@ -444,7 +444,7 @@ public class MetaInfo
/**
* The creation date (ms) or zero.
* Not available for locally-created torrents.
* As of 0.9.19, available for locally-created torrents.
* @since 0.9.7
*/
public long getCreationDate() {
@@ -595,6 +595,14 @@ public class MetaInfo
m.put("announce", announce);
if (announce_list != null)
m.put("announce-list", announce_list);
// misc. optional top-level stuff
if (comment != null)
m.put("comment", comment);
if (created_by != null)
m.put("created by", created_by);
if (creation_date != 0)
m.put("creation date", creation_date / 1000);
Map<String, BEValue> info = createInfoMap();
m.put("info", info);
// don't save this locally, we should only do this once

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

@@ -75,6 +75,8 @@ class PeerCheckerTask implements Runnable
List<Peer> removed = new ArrayList<Peer>();
int uploadLimit = coordinator.allowedUploaders();
boolean overBWLimit = coordinator.overUpBWLimit();
if (_log.shouldLog(Log.DEBUG))
_log.debug("peers: " + peerList.size() + " limit: " + uploadLimit + " overBW? " + overBWLimit);
DHT dht = _util.getDHT();
for (Peer peer : peerList) {

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);
}
}
@@ -234,7 +244,7 @@ class PeerConnectionOut implements Runnable
{
synchronized(sendQueue)
{
sendQueue.add(m);
sendQueue.offer(m);
sendQueue.notifyAll();
}
}
@@ -278,11 +288,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 +318,7 @@ class PeerConnectionOut implements Runnable
synchronized(sendQueue)
{
if(sendQueue.isEmpty())
sendQueue.add(m);
sendQueue.offer(m);
sendQueue.notifyAll();
}
}
@@ -350,12 +371,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 +508,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 +538,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 +551,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 +592,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

@@ -25,14 +25,15 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicLong;
import net.i2p.I2PAppContext;
import net.i2p.data.ByteArray;
@@ -52,7 +53,7 @@ import org.klomp.snark.dht.DHT;
*/
class PeerCoordinator implements PeerListener
{
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerCoordinator.class);
private final Log _log;
/**
* External use by PeerMonitorTask only.
@@ -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};
@@ -98,7 +99,7 @@ class PeerCoordinator implements PeerListener
* This is a Queue, not a Set, because PeerCheckerTask keeps things in order for choking/unchoking.
* External use by PeerMonitorTask only.
*/
final Queue<Peer> peers;
final Deque<Peer> peers;
/**
* Peers we heard about via PEX
@@ -144,6 +145,7 @@ class PeerCoordinator implements PeerListener
{
_util = util;
_random = util.getContext().random();
_log = util.getContext().logManager().getLog(PeerCoordinator.class);
this.id = id;
this.infohash = infohash;
this.metainfo = metainfo;
@@ -154,7 +156,7 @@ class PeerCoordinator implements PeerListener
wantedPieces = new ArrayList<Piece>();
setWantedPieces();
partialPieces = new ArrayList<PartialPiece>(getMaxConnections() + 1);
peers = new LinkedBlockingQueue<Peer>();
peers = new LinkedBlockingDeque<Peer>();
magnetState = new MagnetState(infohash, metainfo);
pexPeers = new ConcurrentHashSet<PeerID>();
@@ -278,7 +280,7 @@ class PeerCoordinator implements PeerListener
*/
public long getUploaded()
{
return uploaded;
return uploaded.get();
}
/**
@@ -286,7 +288,7 @@ class PeerCoordinator implements PeerListener
* @since 0.9.15
*/
public void setUploaded(long up) {
uploaded = up;
uploaded.set(up);
}
/**
@@ -294,7 +296,7 @@ class PeerCoordinator implements PeerListener
*/
public long getDownloaded()
{
return downloaded;
return downloaded.get();
}
/**
@@ -320,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)
@@ -522,7 +530,10 @@ class PeerCoordinator implements PeerListener
// Can't add to beginning since we converted from a List to a Queue
// We can do this in Java 6 with a Deque
//peers.add(0, peer);
peers.add(peer);
if (_util.getContext().random().nextInt(4) == 0)
peers.push(peer);
else
peers.add(peer);
peerCount = peers.size();
unchokePeer();
@@ -940,7 +951,7 @@ class PeerCoordinator implements PeerListener
*/
public void uploaded(Peer peer, int size)
{
uploaded += size;
uploaded.addAndGet(size);
//if (listener != null)
// listener.peerChange(this, peer);
@@ -951,7 +962,7 @@ class PeerCoordinator implements PeerListener
*/
public void downloaded(Peer peer, int size)
{
downloaded += size;
downloaded.addAndGet(size);
//if (listener != null)
// listener.peerChange(this, peer);
@@ -1000,7 +1011,7 @@ class PeerCoordinator implements PeerListener
else
{
// Oops. We didn't actually download this then... :(
downloaded -= metainfo.getPieceLength(piece);
downloaded.addAndGet(0 - metainfo.getPieceLength(piece));
_log.warn("Got BAD piece " + piece + "/" + metainfo.getPieces() + " from " + peer + " for " + metainfo.getName());
return false; // No need to announce BAD piece to peers.
}
@@ -1461,8 +1472,8 @@ class PeerCoordinator implements PeerListener
public int allowedUploaders()
{
if (listener != null && listener.overUploadLimit(uploaders)) {
// if (_log.shouldLog(Log.DEBUG))
// _log.debug("Over limit, uploaders was: " + uploaders);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Over limit, uploaders was: " + uploaders);
return uploaders - 1;
} else if (uploaders < MAX_UPLOADERS)
return uploaders + 1;

View File

@@ -155,12 +155,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 +185,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,12 +225,17 @@ 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
if (piece < 0
@@ -227,8 +259,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;
}
@@ -536,6 +574,58 @@ 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
* @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) {
for (Iterator<Request> iter = outstandingRequests.iterator(); iter.hasNext(); ) {
Request req = iter.next();
if (req.getPiece() == piece && req.off == begin && req.len == length)
iter.remove();
}
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 +633,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

@@ -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)
@@ -1288,7 +1303,8 @@ public class Snark
totalUploaders += c.uploaders;
}
int limit = _util.getMaxUploaders();
// debug("Total uploaders: " + totalUploaders + " Limit: " + limit, Snark.DEBUG);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Total uploaders: " + totalUploaders + " Limit: " + limit);
return totalUploaders > limit;
}

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";
@@ -118,8 +120,8 @@ public class SnarkManager implements CompleteListener {
public static final String PROP_PRIVATETRACKERS = "i2psnark.privatetrackers";
private static final String PROP_USE_DHT = "i2psnark.enableDHT";
public static final int MIN_UP_BW = 2;
public static final int DEFAULT_MAX_UP_BW = 10;
public static final int MIN_UP_BW = 10;
public static final int DEFAULT_MAX_UP_BW = 25;
public static final int DEFAULT_STARTUP_DELAY = 3;
public static final int DEFAULT_REFRESH_DELAY_SECS = 60;
private static final int DEFAULT_PAGE_SIZE = 50;
@@ -164,7 +166,7 @@ public class SnarkManager implements CompleteListener {
public static final Set<String> DEFAULT_TRACKER_ANNOUNCES;
/** host names for config form */
public static final Set<String> KNOWN_OPENTRACKERS = new HashSet(Arrays.asList(new String[] {
public static final Set<String> KNOWN_OPENTRACKERS = new HashSet<String>(Arrays.asList(new String[] {
"tracker.welterde.i2p", "cfmqlafjfmgkzbt4r3jsfyhgsr5abgxryl6fnz3d3y5a365di5aa.b32.i2p",
"opentracker.dg2.i2p", "w7tpbzncbcocrqtwwm3nezhnnsw4ozadvi2hmvzdhrqzfxfum7wa.b32.i2p",
"tracker.thebland.i2p", "s5ikrdyjwbcgxmqetxb3nyheizftms7euacuub2hic7defkh3xhq.b32.i2p",
@@ -175,7 +177,7 @@ public class SnarkManager implements CompleteListener {
}));
static {
Set<String> ann = new HashSet();
Set<String> ann = new HashSet<String>(8);
for (int i = 1; i < DEFAULT_TRACKERS.length; i += 2) {
if (DEFAULT_TRACKERS[i-1].equals("TheBland") && !SigType.ECDSA_SHA256_P256.isAvailable())
continue;
@@ -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) {
@@ -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

@@ -36,7 +36,9 @@ import java.util.Locale;
import java.util.Random;
import java.util.Set;
import net.i2p.crypto.SigType;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.ConvertToHash;
import net.i2p.util.I2PAppThread;
@@ -88,6 +90,8 @@ public class TrackerClient implements Runnable {
private static final int DHT_ANNOUNCE_PEERS = 4;
public static final int PORT = 6881;
private static final int MAX_TRACKERS = 12;
// tracker.welterde.i2p
private static final Hash DSA_ONLY_TRACKER = ConvertToHash.getHash("cfmqlafjfmgkzbt4r3jsfyhgsr5abgxryl6fnz3d3y5a365di5aa.b32.i2p");
private final I2PSnarkUtil _util;
private final MetaInfo meta;
@@ -156,6 +160,7 @@ public class TrackerClient implements Runnable {
consecutiveFails = 0;
runStarted = false;
_fastUnannounce = false;
snark.setTrackerProblems(null);
_thread = new I2PAppThread(this, _threadName + " #" + (++_runCount), true);
_thread.start();
started = true;
@@ -362,12 +367,21 @@ public class TrackerClient implements Runnable {
if (h == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Bad announce URL: [" + ann + ']');
return false;
return false;
}
// comment this out if tracker.welterde.i2p upgrades
if (h.equals(DSA_ONLY_TRACKER)) {
Destination dest = _util.getMyDestination();
if (dest != null && dest.getSigType() != SigType.DSA_SHA1) {
if (_log.shouldLog(Log.WARN))
_log.warn("Skipping incompatible tracker: " + ann);
return false;
}
}
if (existing.size() >= MAX_TRACKERS) {
if (_log.shouldLog(Log.INFO))
_log.info("Not using announce URL, we have enough: [" + ann + ']');
return false;
return false;
}
boolean rv = existing.add(h);
if (!rv) {
@@ -528,9 +542,9 @@ public class TrackerClient implements Runnable {
!snark.isChecking() &&
info.getSeedCount() > 100 &&
coordinator.getPeerCount() <= 0 &&
_util.getContext().clock().now() > _startedOn + 2*60*60*1000 &&
_util.getContext().clock().now() > _startedOn + 30*60*1000 &&
snark.getTotalLength() > 0 &&
uploaded >= snark.getTotalLength() * 5 / 4) {
uploaded >= snark.getTotalLength() / 2) {
if (_log.shouldLog(Log.WARN))
_log.warn("Auto stopping " + snark.getBaseName());
snark.setAutoStoppable(false);
@@ -898,7 +912,7 @@ public class TrackerClient implements Runnable {
if (path == null || path.length() < 517 ||
!path.startsWith("/"))
return null;
String[] parts = path.substring(1).split("/?&;", 2);
String[] parts = path.substring(1).split("[/\\?&;]", 2);
return ConvertToHash.getHash(parts[0]);
}
return null;

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

@@ -842,7 +842,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
if (_log.shouldLog(Log.INFO))
_log.info("Sending error " + msg + " to: " + nInfo);
Map<String, Object> map = new HashMap<String, Object>(4);
List<Object> error = new ArrayList(2);
List<Object> error = new ArrayList<Object>(2);
error.add(Integer.valueOf(err));
error.add(msg);
map.put("e", error);
@@ -1294,7 +1294,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
} else {
List<byte[]> hashes;
if (peers.isEmpty()) {
hashes = Collections.EMPTY_LIST;
hashes = Collections.emptyList();
} else {
hashes = new ArrayList<byte[]>(peers.size());
for (Hash peer : peers) {

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

@@ -0,0 +1,8 @@
<html>
<body>
<p>
I2P version of the snark bittorrent client, imported in 2005 and heavily enhanced
to add a web UI, DHT support, and other features.
</p>
</body>
</html>

View File

@@ -358,6 +358,7 @@ class BasicServlet extends HttpServlet
writeHeaders(response, content, content_length);
response.setStatus(416);
response.setHeader("Content-Range", InclusiveByteRange.to416HeaderRangeString(content_length));
in.close();
return;
}

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()) {
@@ -1095,7 +1108,7 @@ public class I2PSnarkServlet extends BasicServlet {
}
}
} else if ("Save".equals(action)) {
String dataDir = req.getParameter("dataDir");
String dataDir = req.getParameter("nofilter_dataDir");
boolean filesPublic = req.getParameter("filesPublic") != null;
boolean autoStart = req.getParameter("autoStart") != null;
String seedPct = req.getParameter("seedPct");
@@ -2138,7 +2151,8 @@ public class I2PSnarkServlet extends BasicServlet {
"<table border=\"0\"><tr><td>");
out.write(_("Data directory"));
out.write(": <td><input name=\"dataDir\" size=\"80\" value=\"" + dataDir + "\" spellcheck=\"false\"></td>\n" +
out.write(": <td><input name=\"nofilter_dataDir\" size=\"80\" value=\"" +
DataHelper.escapeHTML(dataDir) + "\" spellcheck=\"false\"></td>\n" +
"<tr><td>");
out.write(_("Files readable by all"));
@@ -2268,13 +2282,13 @@ public class I2PSnarkServlet extends BasicServlet {
out.write("<tr><td>");
out.write(_("Inbound Settings"));
out.write(":<td>");
out.write(renderOptions(1, 6, 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, 6, 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));
@@ -2693,7 +2707,7 @@ public class I2PSnarkServlet extends BasicServlet {
buf.append("&nbsp;<b>")
.append(_("Info hash"))
.append(":</b> ")
.append(hex)
.append(hex.toUpperCase(Locale.US))
.append("</td></tr>\n");
String announce = null;

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
The i2psnark user interface, implemented as a webapp in i2psnark.war.
</p>
</body>
</html>

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

@@ -9,6 +9,7 @@ flac = audio/flac
flv = video/x-flv
iso = application/x-iso9660-image
m4a = audio/mp4a-latm
m4b = audio/mp4a-latm
m4v = video/x-m4v
mkv = video/x-matroska
mobi = application/x-mobipocket-ebook

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

@@ -62,7 +62,7 @@
<target name="jar" depends="builddep, compile, bundle-proxy, jarUpToDate, listChangedFiles" unless="jar.uptodate" >
<!-- set if unset -->
<property name="workspace.changes.j.tr" value="" />
<jar destfile="./build/i2ptunnel.jar" basedir="./build/obj" includes="**/*.class" excludes="**/EditBean.class **/IndexBean.class" >
<jar destfile="./build/i2ptunnel.jar" basedir="./build/obj" includes="**/*.class" excludes="**/ui/*.class **/EditBean.class **/IndexBean.class" >
<manifest>
<attribute name="Main-Class" value="net.i2p.i2ptunnel.I2PTunnel" />
<attribute name="Class-Path" value="i2p.jar mstreaming.jar" />
@@ -73,7 +73,7 @@
<attribute name="Workspace-Changes" value="${workspace.changes.j.tr}" />
</manifest>
</jar>
<jar destfile="./build/temp-beans.jar" basedir="./build/obj" includes="**/EditBean.class **/IndexBean.class" />
<jar destfile="./build/temp-beans.jar" basedir="./build/obj" includes="**/ui/*.class **/EditBean.class **/IndexBean.class" />
</target>
<target name="jarUpToDate">
@@ -90,6 +90,36 @@
</condition>
</target>
<!-- Separate jar for general UI classes -->
<target name="uiJar" depends="jar, uiJarUpToDate, listChangedFiles" unless="uiJar.uptodate" >
<!-- set if unset -->
<property name="workspace.changes.j.tr" value="" />
<jar destfile="./build/i2ptunnel-ui.jar" basedir="./build/obj" includes="**/ui/*.class" >
<manifest>
<attribute name="Class-Path" value="i2p.jar mstreaming.jar i2ptunnel.jar" />
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />
<attribute name="Base-Revision" value="${workspace.version}" />
<attribute name="Workspace-Changes" value="${workspace.changes.j.tr}" />
</manifest>
</jar>
</target>
<target name="uiJarUpToDate">
<uptodate property="uiJar.uptodate" targetfile="build/i2ptunnel-ui.jar" >
<srcfiles dir= "build/obj" includes="**/ui/*.class" />
</uptodate>
<condition property="shouldListChanges" >
<and>
<not>
<isset property="uiJar.uptodate" />
</not>
<isset property="mtn.available" />
</and>
</condition>
</target>
<!-- servlet translations go in the war, not the jar -->
<target name="bundle" depends="compile, precompilejsp" unless="no.bundle">
<!-- Update the messages_*.po files.
@@ -185,6 +215,9 @@
<target name="war" depends="precompilejsp, bundle, warUpToDate, listChangedFiles2" unless="war.uptodate" >
<!-- set if unset -->
<property name="workspace.changes.w.tr" value="" />
<copy todir="../jsp/WEB-INF/classes/net/i2p/i2ptunnel/ui">
<fileset dir="build/obj/net/i2p/i2ptunnel/ui" />
</copy>
<copy file="build/obj/net/i2p/i2ptunnel/web/EditBean.class" todir="../jsp/WEB-INF/classes/net/i2p/i2ptunnel/web" />
<copy file="build/obj/net/i2p/i2ptunnel/web/IndexBean.class" todir="../jsp/WEB-INF/classes/net/i2p/i2ptunnel/web" />
<war destfile="build/i2ptunnel.war" webxml="../jsp/web-out.xml"

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,19 +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.Log;
import net.i2p.util.ReusableGZIPInputStream;
/**
* This does the transparent gzip decompression on the client side.
@@ -151,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++) {
@@ -162,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 + "]");
@@ -196,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 ");
@@ -244,83 +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);
// 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 {
I2PTunnelClientBase.getClientExecutor().execute(new Pusher(pi, out));
} catch (RejectedExecutionException ree) {
// shouldn't happen
throw ree;
}
out = po;
}
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), 0);
_context.statManager().addRateData("i2ptunnel.httpCompressed", (long)compressed, 0);
_context.statManager().addRateData("i2ptunnel.httpExpanded", (long)expanded, 0);
}
}
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;
@@ -83,7 +82,7 @@ import net.i2p.util.OrderedProperties;
* An I2PTunnel tracks one or more I2PTunnelTasks and one or more I2PSessions.
* Usually one of each.
*
* Todo: Most events are not listened to elsewhere, so error propagation is poor
* TODO: Most events are not listened to elsewhere, so error propagation is poor
*/
public class I2PTunnel extends EventDispatcherImpl implements Logging {
private final Log _log;
@@ -540,6 +539,8 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
* This DOES update a running TunnelTask, but NOT the session.
* A more efficient runClientOptions().
*
* Defaults in opts properties are not recommended, they may or may not be honored.
*
* @param opts non-null
* @since 0.9.1
*/
@@ -885,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) {
@@ -964,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) {
@@ -1033,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 +
@@ -1095,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) {
@@ -1158,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) {
@@ -1205,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) {
@@ -1324,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");
}
}
@@ -1508,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");
}
@@ -1596,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);
@@ -1662,7 +1670,14 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
private void runPing(String allargs, Logging l) {
if (allargs.length() != 0) {
_clientOptions.setProperty(I2Ping.PROP_COMMAND, allargs);
I2PTunnelTask task = new I2Ping(l, ownDest, this, this);
if (ownDest) {
if (!_clientOptions.containsKey("inbound.nickname"))
_clientOptions.setProperty("inbound.nickname", "I2Ping");
if (!_clientOptions.containsKey("outbound.nickname"))
_clientOptions.setProperty("outbound.nickname", "I2Ping");
}
I2PTunnelClientBase task = new I2Ping(l, ownDest, this, this);
task.startRunning();
addtask(task);
notifyEvent("pingTaskId", Integer.valueOf(task.getId()));
} else {
@@ -1739,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);
}
/**
@@ -1758,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);
@@ -1782,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) {
@@ -1797,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");
}
@@ -122,9 +117,11 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
int port = addr.getPort();
i2ps = createI2PSocket(clientDest, port);
i2ps.setReadTimeout(readTimeout);
Thread t = new I2PTunnelRunner(s, i2ps, sockLock, null, null, mySockets,
I2PTunnelRunner t = new I2PTunnelRunner(s, i2ps, sockLock, null, null, mySockets,
(I2PTunnelRunner.FailCallback) null);
t.start();
// we are called from an unlimited thread pool, so run inline
//t.start();
t.run();
} catch (Exception ex) {
if (_log.shouldLog(Log.INFO))
_log.info("Error connecting", ex);

View File

@@ -16,12 +16,8 @@ import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
import javax.net.ssl.SSLServerSocket;
@@ -29,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;
@@ -56,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.
@@ -77,24 +77,26 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
// true if we are chained from a server.
private boolean chained;
/** how long to wait before dropping an idle thread */
private static final long HANDLER_KEEPALIVE_MS = 2*60*1000;
private volatile ThreadPoolExecutor _executor;
/** this is ONLY for shared clients */
private static I2PSocketManager socketManager;
/**
* We keep a static pool of socket handlers for all clients,
* as there is no need for isolation on the client side.
* Extending classes may use it for other purposes.
* Not for use by servers, as there is no limit on threads.
* Only destroy and replace a static shared client socket manager if it's been connected before
* @since 0.9.20
*/
private static volatile ThreadPoolExecutor _executor;
private static int _executorThreadCount;
private static final Object _executorLock = new Object();
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
@@ -106,46 +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());
synchronized (_executorLock) {
if (_executor == null)
_executor = new CustomThreadPoolExecutor();
}
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
@@ -159,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
@@ -175,20 +161,12 @@ 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());
synchronized (_executorLock) {
if (_executor == null)
_executor = new CustomThreadPoolExecutor();
}
// normalize path so we can find it
if (pkf != null) {
File keyFile = new File(pkf);
@@ -205,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.
*
@@ -294,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
@@ -314,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
@@ -326,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
@@ -337,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 + "]");
@@ -357,12 +305,56 @@ 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;
}
/**
* This may take a LONG time.
* 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
*
* @since 0.9.18
*/
protected static synchronized void killSharedClient() {
socketManager = null;
}
/**
* 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
@@ -371,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
@@ -386,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
@@ -398,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
@@ -415,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))
@@ -468,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;
}
@@ -484,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();
@@ -597,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) {
@@ -640,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,49 +738,36 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
}
TunnelControllerGroup tcg = TunnelControllerGroup.getInstance();
if (tcg != null) {
_executor = tcg.getClientExecutor();
} 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.
// Never shut down.
_executor = new TunnelControllerGroup.CustomThreadPoolExecutor();
}
while (open) {
Socket s = ss.accept();
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();
}
}
}
/**
* @return may be null if no class has been instantiated
* @since 0.8.8
*/
static ThreadPoolExecutor getClientExecutor() {
return _executor;
}
/**
* @since 0.8.8
*/
static void killClientExecutor() {
synchronized (_executorLock) {
if (_executor != null) {
_executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
_executor.shutdownNow();
_executor = null;
}
// kill the shared client, so that on restart in android
// we won't latch onto the old one
socketManager = null;
}
}
/**
* Manage the connection just opened on the specified socket
*
@@ -721,37 +793,36 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
}
}
/**
* Not really needed for now but in case we want to add some hooks like afterExecute().
*/
private static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
public CustomThreadPoolExecutor() {
super(0, Integer.MAX_VALUE, HANDLER_KEEPALIVE_MS, TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>(), new CustomThreadFactory());
}
}
/** just to set the name and set Daemon */
private static class CustomThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
Thread rv = Executors.defaultThreadFactory().newThread(r);
rv.setName("I2PTunnel Client Runner " + (++_executorThreadCount));
rv.setDaemon(true);
return rv;
}
}
/**
* 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);
@@ -787,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.");
@@ -822,7 +893,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
/**
* Manage a connection in a separate thread. This only works if
* you do not override manageConnection()
* you do not override manageConnection().
*
* This is run in a thread from an unlimited-size thread pool,
* so it may block or run indefinitely.
*/
protected abstract void clientConnectionRun(Socket s);
}

View File

@@ -59,26 +59,31 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
public static final String AUTH_REALM = "I2P SSL Proxy";
private final static byte[] ERR_BAD_PROTOCOL =
("HTTP/1.1 405 Bad Method\r\n"+
private final static String ERR_BAD_PROTOCOL =
"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. "+
"The Connect Proxy supports CONNECT requests ONLY. Other methods such as GET are not allowed - Maybe you wanted the HTTP Proxy?.<BR>")
.getBytes();
"The Connect Proxy supports CONNECT requests ONLY. Other methods such as GET are not allowed - Maybe you wanted the HTTP Proxy?.<BR>";
private final static byte[] ERR_LOCALHOST =
("HTTP/1.1 403 Access Denied\r\n"+
private final static String ERR_LOCALHOST =
"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>")
.getBytes();
"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
*/
@@ -87,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())
@@ -99,8 +99,6 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
}
setName("HTTPS Proxy on " + tunnel.listenHost + ':' + localPort);
startRunning();
}
/**
@@ -126,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
@@ -273,7 +272,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
Destination clientDest = _context.namingService().lookup(destination);
if (clientDest == null) {
byte[] header;
String header;
if (usingWWWProxy)
header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN);
else
@@ -289,10 +288,12 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
if (usingWWWProxy)
data = newRequest.toString().getBytes("ISO-8859-1");
else
response = SUCCESS_RESPONSE;
response = SUCCESS_RESPONSE.getBytes("UTF-8");
OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
Thread t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
t.start();
// we are called from an unlimited thread pool, so run inline
//t.start();
t.run();
} catch (IOException ex) {
_log.info(getPrefix(requestId) + "Error trying to connect", ex);
handleClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
@@ -309,10 +310,10 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
}
}
private static void writeErrorMessage(byte[] errMessage, OutputStream out) throws IOException {
private static void writeErrorMessage(String errMessage, OutputStream out) throws IOException {
if (out == null)
return;
out.write(errMessage);
out.write(errMessage.getBytes("UTF-8"));
writeFooter(out);
}
}

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

@@ -3,9 +3,12 @@
*/
package net.i2p.i2ptunnel;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;
import java.net.SocketException;
import java.net.URI;
@@ -84,13 +87,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
/**
* These are backups if the xxx.ht error page is missing.
*/
private final static byte[] ERR_REQUEST_DENIED =
("HTTP/1.1 403 Access Denied\r\n" +
private final static String ERR_REQUEST_DENIED =
"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>").getBytes();
"You attempted to connect to a non-I2P website or location.<BR>";
/*****
private final static byte[] ERR_TIMEOUT =
@@ -105,90 +110,109 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"the following Destination:<BR><BR>")
.getBytes();
*****/
private final static byte[] ERR_NO_OUTPROXY =
("HTTP/1.1 503 Service Unavailable\r\n" +
private final static String ERR_NO_OUTPROXY =
"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 " +
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel").getBytes();
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel";
private final static byte[] ERR_AHELPER_CONFLICT =
("HTTP/1.1 409 Conflict\r\n" +
private final static String ERR_AHELPER_CONFLICT =
"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 " +
"than a host entry in your host database. " +
"Someone could be trying to impersonate another eepsite, " +
"or people have given two eepsites identical names.<p>" +
"Someone could be trying to impersonate another website, " +
"or people have given two websites identical names.<p>" +
"You can resolve the conflict by considering which key you trust, " +
"and either discarding the addresshelper link, " +
"discarding the host entry from your host database, " +
"or naming one of them differently.<p>").getBytes();
"or naming one of them differently.<p>";
private final static byte[] ERR_AHELPER_NOTFOUND =
("HTTP/1.1 404 Not Found\r\n" +
private final static String ERR_AHELPER_NOTFOUND =
"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. " +
"It seems to be garbage data, or a mistyped b32. Check your URL " +
"to try and fix the helper key to be either a b32 or a base64.").getBytes();
"to try and fix the helper key to be either a b32 or a base64.";
private final static byte[] ERR_AHELPER_NEW =
("HTTP/1.1 409 New Address\r\n" +
private final static String ERR_AHELPER_NEW =
"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. " +
"You may either save the destination for this host name to your address book, or remember it only until your router restarts. " +
"If you save it to your address book, you will not see this message again. " +
"If you do not wish to visit this host, click the \"back\" button on your browser.").getBytes();
"If you do not wish to visit this host, click the \"back\" button on your browser.";
private final static byte[] ERR_BAD_PROTOCOL =
("HTTP/1.1 403 Bad Protocol\r\n" +
private final static String ERR_BAD_PROTOCOL =
"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. " +
"The I2P HTTP Proxy supports HTTP and HTTPS requests only. Other protocols such as FTP are not allowed.<BR>").getBytes();
"The I2P HTTP Proxy supports HTTP and HTTPS requests only. Other protocols such as FTP are not allowed.<BR>";
private final static byte[] ERR_BAD_URI =
("HTTP/1.1 403 Bad URI\r\n" +
private final static String ERR_BAD_URI =
"HTTP/1.1 403 Bad URI\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
"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. " +
"If you clicked e.g. a forum link, check the end of the URI for any characters the browser has mistakenly added on.<BR>").getBytes();
"If you clicked e.g. a forum link, check the end of the URI for any characters the browser has mistakenly added on.<BR>";
private final static byte[] ERR_LOCALHOST =
("HTTP/1.1 403 Access Denied\r\n" +
private final static String ERR_LOCALHOST =
"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>").getBytes();
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>";
private final static byte[] ERR_INTERNAL_SSL =
("HTTP/1.1 403 SSL Rejected\r\n" +
private final static String ERR_INTERNAL_SSL =
"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." +
"You may change the configuration in I2PTunnel").getBytes();
"You may change the configuration in I2PTunnel";
/**
* 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) {
@@ -197,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
*/
@@ -213,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, ", ");
@@ -226,9 +247,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
setName("HTTP Proxy on " + tunnel.listenHost + ':' + localPort);
startRunning();
notifyEvent("openHTTPClientResult", "ok");
}
@@ -293,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);
}
}
/**
@@ -303,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();
@@ -464,10 +491,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Bad request [" + request + "]", use);
}
out.write(getErrorPage("baduri", ERR_BAD_URI));
writeFooter(out);
reader.drain();
s.close();
try {
out.write(getErrorPage("baduri", ERR_BAD_URI).getBytes("UTF-8"));
writeFooter(out);
reader.drain();
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
return;
}
@@ -596,12 +628,20 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Could not find destination for " + ahelperKey);
}
byte[] header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
out.write(header);
out.write(("<p>" + _("This seems to be a bad destination:") + " " + ahelperKey + " " + _("i2paddresshelper cannot help you with a destination like that!") + "</p>").getBytes("UTF-8"));
writeFooter(out);
// XXX: should closeSocket(s) be in a finally block?
closeSocket(s);
String header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
try {
out.write(header.getBytes("UTF-8"));
out.write(("<p>" + _("This seems to be a bad destination:") + " " + ahelperKey + " " +
_("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
} finally {
closeSocket(s);
}
return;
}
ahelperKey = _dest.toBase64();
@@ -614,7 +654,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
// Store in local HashMap unless there is conflict
String old = addressHelpers.putIfAbsent(destination.toLowerCase(Locale.US), ahelperKey);
ahelperNew = old == null;
if((!ahelperNew) && !old.equals(ahelperKey)) {
// inr address helper links without trailing '=', so omit from comparison
if ((!ahelperNew) && !old.replace("=", "").equals(ahelperKey.replace("=", ""))) {
// Conflict: handle when URL reconstruction done
ahelperConflict = true;
if(_log.shouldLog(Log.WARN)) {
@@ -644,11 +685,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
// Did addresshelper key conflict?
if(ahelperConflict) {
try {
// convert ahelperKey to b32
String alias = getHostName(ahelperKey);
if(alias.equals("i2p")) {
// bad ahelperKey
byte[] header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
String header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
writeErrorMessage(header, out, targetRequest, false, destination);
} else {
String trustedURL = requestURI.toASCIIString();
@@ -662,14 +704,19 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
break;
}
String conflictURL = conflictURI.toASCIIString();
byte[] header = getErrorPage("ahelper-conflict", ERR_AHELPER_CONFLICT);
out.write(header);
out.write(_("To visit the destination in your host database, click <a href=\"{0}\">here</a>. To visit the conflicting addresshelper destination, click <a href=\"{1}\">here</a>.", trustedURL, conflictURL).getBytes("UTF-8"));
out.write(("</p></div>").getBytes());
String header = getErrorPage("ahelper-conflict", ERR_AHELPER_CONFLICT);
out.write(header.getBytes("UTF-8"));
out.write(_("To visit the destination in your host database, click <a href=\"{0}\">here</a>. To visit the conflicting addresshelper destination, click <a href=\"{1}\">here</a>.",
trustedURL, conflictURL).getBytes("UTF-8"));
out.write("</p></div>".getBytes("UTF-8"));
writeFooter(out);
}
reader.drain();
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
reader.drain();
s.close();
return;
}
} // end query processing
@@ -699,10 +746,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
} else if(hostLowerCase.equals("localhost") || host.equals("127.0.0.1") ||
host.startsWith("192.168.") || host.equals("[::1]")) {
// if somebody is trying to get to 192.168.example.com, oh well
out.write(getErrorPage("localhost", ERR_LOCALHOST));
writeFooter(out);
reader.drain();
s.close();
try {
out.write(getErrorPage("localhost", ERR_LOCALHOST).getBytes("UTF-8"));
writeFooter(out);
reader.drain();
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
return;
} else if(host.contains(".") || host.startsWith("[")) {
if (Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_USE_OUTPROXY_PLUGIN, "true"))) {
@@ -747,10 +799,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
_log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
}
l.log("No outproxy found for the request.");
out.write(getErrorPage("noproxy", ERR_NO_OUTPROXY));
writeFooter(out);
reader.drain();
s.close();
try {
out.write(getErrorPage("noproxy", ERR_NO_OUTPROXY).getBytes("UTF-8"));
writeFooter(out);
reader.drain();
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
return;
}
destination = currentProxy;
@@ -768,10 +825,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(_log.shouldLog(Log.WARN)) {
_log.warn("NODOTS, NOI2P: " + request);
}
out.write(getErrorPage("denied", ERR_REQUEST_DENIED));
writeFooter(out);
reader.drain();
s.close();
try {
out.write(getErrorPage("denied", ERR_REQUEST_DENIED).getBytes("UTF-8"));
writeFooter(out);
reader.drain();
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
return;
} // end host name processing
@@ -897,7 +959,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
pw = getTunnel().getClientOptions().getProperty(PROP_OUTPROXY_PW);
}
if(user != null && pw != null) {
newRequest.append("Proxy-Authorization: Basic ").append(Base64.encode((user + ':' + pw).getBytes(), true)) // true = use standard alphabet
newRequest.append("Proxy-Authorization: Basic ")
.append(Base64.encode((user + ':' + pw).getBytes("UTF-8"), true)) // true = use standard alphabet
.append("\r\n");
}
}
@@ -914,13 +977,18 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(method == null || (destination == null && !usingInternalOutproxy)) {
//l.log("No HTTP method found in the request.");
if (protocol != null && "http".equals(protocol.toLowerCase(Locale.US))) {
out.write(getErrorPage("denied", ERR_REQUEST_DENIED));
} else {
out.write(getErrorPage("protocol", ERR_BAD_PROTOCOL));
try {
if (protocol != null && "http".equals(protocol.toLowerCase(Locale.US))) {
out.write(getErrorPage("denied", ERR_REQUEST_DENIED).getBytes("UTF-8"));
} else {
out.write(getErrorPage("protocol", ERR_BAD_PROTOCOL).getBytes("UTF-8"));
}
writeFooter(out);
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
writeFooter(out);
s.close();
return;
}
@@ -938,23 +1006,33 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
_log.warn(getPrefix(requestId) + "Auth required, sending 407");
}
}
out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes());
writeFooter(out);
s.close();
try {
out.write(getAuthError(result == AuthResult.AUTH_STALE).getBytes("UTF-8"));
writeFooter(out);
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
return;
}
// Serve local proxy files (images, css linked from error pages)
// Ignore all the headers
if(usingInternalServer) {
// disable the add form if address helper is disabled
if(internalPath.equals("/add") &&
Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
out.write(ERR_HELPER_DISABLED);
} else {
LocalHTTPServer.serveLocalFile(out, method, internalPath, internalRawQuery, _proxyNonce);
if (usingInternalServer) {
try {
// disable the add form if address helper is disabled
if(internalPath.equals("/add") &&
Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
out.write(ERR_HELPER_DISABLED.getBytes("UTF-8"));
} else {
LocalHTTPServer.serveLocalFile(out, method, internalPath, internalRawQuery, _proxyNonce);
}
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
s.close();
return;
}
@@ -966,13 +1044,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
byte[] response;
if (method.toUpperCase(Locale.US).equals("CONNECT")) {
data = null;
response = SUCCESS_RESPONSE;
response = SUCCESS_RESPONSE.getBytes("UTF-8");
} else {
data = newRequest.toString().getBytes("ISO-8859-1");
response = null;
}
Thread t = new I2PTunnelOutproxyRunner(s, outSocket, sockLock, data, response, onTimeout);
t.start();
// we are called from an unlimited thread pool, so run inline
//t.start();
t.run();
return;
}
@@ -990,9 +1070,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(_log.shouldLog(Log.WARN)) {
_log.warn(getPrefix(requestId) + "Could not find destination for " + addressHelper);
}
byte[] header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
writeErrorMessage(header, out, targetRequest, false, destination);
s.close();
String header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND);
try {
writeErrorMessage(header, out, targetRequest, false, destination);
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
return;
}
} else if("i2p".equals(host)) {
@@ -1022,7 +1107,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(_log.shouldLog(Log.WARN)) {
_log.warn("Unable to resolve " + destination + " (proxy? " + usingWWWProxy + ", request: " + targetRequest);
}
byte[] header;
String header;
String jumpServers = null;
String extraMessage = null;
if(usingWWWProxy) {
@@ -1039,16 +1124,26 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
jumpServers = DEFAULT_JUMP_SERVERS;
}
}
writeErrorMessage(header, extraMessage, out, targetRequest, usingWWWProxy, destination, jumpServers);
s.close();
try {
writeErrorMessage(header, extraMessage, out, targetRequest, usingWWWProxy, destination, jumpServers);
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
return;
}
if (method.toUpperCase(Locale.US).equals("CONNECT") &&
!usingWWWProxy &&
!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_INTERNAL_SSL))) {
writeErrorMessage(ERR_INTERNAL_SSL, out, targetRequest, false, destination);
s.close();
try {
writeErrorMessage(ERR_INTERNAL_SSL, out, targetRequest, false, destination);
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
if (_log.shouldLog(Log.WARN))
_log.warn("SSL to i2p destinations denied by configuration: " + targetRequest);
return;
@@ -1060,8 +1155,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(ahelperNew && "GET".equals(method) &&
(userAgent == null || !userAgent.startsWith("Wget")) &&
!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER))) {
writeHelperSaveForm(out, destination, ahelperKey, targetRequest, referer);
s.close();
try {
writeHelperSaveForm(out, destination, ahelperKey, targetRequest, referer);
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
return;
}
@@ -1074,10 +1174,17 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
if(_log.shouldLog(Log.DEBUG)) {
_log.debug("Auto redirecting to " + uri);
}
out.write(("HTTP/1.1 301 Address Helper Accepted\r\n" +
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"));
s.close();
} catch (IOException ioe) {
// ignore
} finally {
closeSocket(s);
}
return;
}
@@ -1091,6 +1198,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
sktOpts.setPort(remotePort);
I2PSocket i2ps = createI2PSocket(clientDest, sktOpts);
OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
Thread t;
if (method.toUpperCase(Locale.US).equals("CONNECT")) {
byte[] data;
byte[] response;
@@ -1099,15 +1207,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
response = null;
} else {
data = null;
response = SUCCESS_RESPONSE;
response = SUCCESS_RESPONSE.getBytes("UTF-8");
}
Thread t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
t.start();
t = new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout);
} else {
byte[] data = newRequest.toString().getBytes("ISO-8859-1");
Thread t = new I2PTunnelHTTPClientRunner(s, i2ps, sockLock, data, mySockets, onTimeout);
t.start();
t = new I2PTunnelHTTPClientRunner(s, i2ps, sockLock, data, mySockets, onTimeout);
}
// we are called from an unlimited thread pool, so run inline
//t.start();
t.run();
} catch(IOException ex) {
if(_log.shouldLog(Log.INFO)) {
_log.info(getPrefix(requestId) + "Error trying to connect", ex);
@@ -1141,7 +1250,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
String s = getTunnel().getClientOptions().getProperty(PROP_SSL_OUTPROXIES);
if (s == null)
return null;
String[] p = s.split(", ");
String[] p = s.split("[,; \r\n\t]");
if (p.length == 0)
return null;
// todo doesn't check for ""
@@ -1152,22 +1261,22 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
/** @since 0.8.7 */
private void writeHelperSaveForm(OutputStream out, String destination, String ahelperKey,
private void writeHelperSaveForm(OutputStream outs, String destination, String ahelperKey,
String targetRequest, String referer) throws IOException {
if(out == null) {
if(outs == null)
return;
}
byte[] header = getErrorPage("ahelper-new", ERR_AHELPER_NEW);
Writer out = new BufferedWriter(new OutputStreamWriter(outs, "UTF-8"));
String header = getErrorPage("ahelper-new", ERR_AHELPER_NEW);
out.write(header);
out.write(("<table><tr><td class=\"mediumtags\" align=\"right\">" + _("Host") +
"</td><td class=\"mediumtags\">" + destination + "</td></tr>\n").getBytes());
out.write("<table><tr><td class=\"mediumtags\" align=\"right\">" + _("Host") +
"</td><td class=\"mediumtags\">" + destination + "</td></tr>\n");
try {
String b32 = Base32.encode(SHA256Generator.getInstance().calculateHash(Base64.decode(ahelperKey)).getData());
out.write(("<tr><td class=\"mediumtags\" align=\"right\">" + _("Base 32") + "</td>" +
"<td><a href=\"http://" + b32 + ".b32.i2p/\">" + b32 + ".b32.i2p</a></td></tr>").getBytes());
out.write("<tr><td class=\"mediumtags\" align=\"right\">" + _("Base 32") + "</td>" +
"<td><a href=\"http://" + b32 + ".b32.i2p/\">" + b32 + ".b32.i2p</a></td></tr>");
} catch(Exception e) {
}
out.write(("<tr><td class=\"mediumtags\" align=\"right\">" + _("Destination") + "</td><td>" +
out.write("<tr><td class=\"mediumtags\" align=\"right\">" + _("Destination") + "</td><td>" +
"<textarea rows=\"1\" style=\"height: 4em; min-width: 0; min-height: 0;\" cols=\"70\" wrap=\"off\" readonly=\"readonly\" >" +
ahelperKey + "</textarea></td></tr></table>\n" +
"<hr><div class=\"formaction\">" +
@@ -1178,18 +1287,19 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"<input type=\"hidden\" name=\"host\" value=\"" + destination + "\">\n" +
"<input type=\"hidden\" name=\"dest\" value=\"" + ahelperKey + "\">\n" +
"<input type=\"hidden\" name=\"nonce\" value=\"" + _proxyNonce + "\">\n" +
"<button type=\"submit\" class=\"accept\" name=\"router\" value=\"router\">" + _("Save {0} to router address book and continue to eepsite", destination) + "</button><br>\n").getBytes("UTF-8"));
"<button type=\"submit\" class=\"accept\" name=\"router\" value=\"router\">" +
_("Save {0} to router address book and continue to website", destination) + "</button><br>\n");
if(_context.namingService().getName().equals("BlockfileNamingService")) {
// only blockfile supports multiple books
out.write(("<br><button type=\"submit\" name=\"master\" value=\"master\">" + _("Save {0} to master address book and continue to eepsite", destination) + "</button><br>\n").getBytes("UTF-8"));
out.write(("<button type=\"submit\" name=\"private\" value=\"private\">" + _("Save {0} to private address book and continue to eepsite", destination) + "</button>\n").getBytes("UTF-8"));
out.write("<br><button type=\"submit\" name=\"master\" value=\"master\">" + _("Save {0} to master address book and continue to website", destination) + "</button><br>\n");
out.write("<button type=\"submit\" name=\"private\" value=\"private\">" + _("Save {0} to private address book and continue to website", destination) + "</button>\n");
}
// Firefox (and others?) don't send referer to meta refresh target, which is
// what the jump servers use, so this isn't that useful.
if (referer != null)
out.write(("<input type=\"hidden\" name=\"referer\" value=\"" + referer + "\">\n").getBytes("UTF-8"));
out.write(("<input type=\"hidden\" name=\"url\" value=\"" + targetRequest + "\">\n" +
"</form></div></div>").getBytes());
out.write("<input type=\"hidden\" name=\"referer\" value=\"" + referer + "\">\n");
out.write("<input type=\"hidden\" name=\"url\" value=\"" + targetRequest + "\">\n" +
"</form></div></div>");
writeFooter(out);
}
@@ -1291,11 +1401,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
return lc.equals("http") || lc.equals("https");
}
private final static byte[] ERR_HELPER_DISABLED =
("HTTP/1.1 403 Disabled\r\n" +
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").getBytes();
"Address helpers disabled";
/**
* Change various parts of the URI.
@@ -1384,7 +1496,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
keystart = i + 1;
valstart = -1;
} else if(c == '=') {
} else if (c == '=' && valstart < 0) {
// end of key
key = query.substring(keystart, i);
valstart = i + 1;
@@ -1394,28 +1506,33 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
/****
private static String[] tests = {
"", "foo", "foo=bar", "&", "&=&", "===", "&&",
"i2paddresshelper=foo",
"i2paddresshelpe=foo",
"2paddresshelper=foo",
"i2paddresshelper=%66oo",
"%692paddresshelper=foo",
"i2paddresshelper=foo&a=b",
"a=b&i2paddresshelper=foo",
"a=b&i2paddresshelper&c=d",
"a=b&i2paddresshelper=foo&c=d",
"a=b;i2paddresshelper=foo;c=d",
"a=b&i2paddresshelper=foo&c"
"", "foo", "foo=bar", "&", "&=&", "===", "&&",
"i2paddresshelper=foo",
"i2paddresshelpe=foo",
"2paddresshelper=foo",
"i2paddresshelper=%66oo",
"%692paddresshelper=foo",
"i2paddresshelper=foo&a=b",
"a=b&i2paddresshelper=foo",
"a=b&i2paddresshelper&c=d",
"a=b&i2paddresshelper=foo&c=d",
"a=b;i2paddresshelper=foo;c=d",
"a=b&i2paddresshelper=foo&c",
"a=b&i2paddresshelper=foo==&c",
"a=b&i2paddresshelper=foo%3d%3d&c",
"a=b&i2paddresshelper=f%6f%6F==&c",
"a=b&i2paddresshelper=foo&i2paddresshelper=bar&c",
"a=b&i2paddresshelper=foo&c%3F%3f%26%3b%3B%3d%3Dc=x%3F%3f%26%3b%3B%3d%3Dx"
};
public static void main(String[] args) {
for (int i = 0; i < tests.length; i++) {
String[] s = removeHelper(tests[i]);
if (s != null)
System.out.println("Test \"" + tests[i] + "\" q=\"" + s[0] + "\" h=\"" + s[1] + "\"");
else
System.out.println("Test \"" + tests[i] + "\" no match");
}
for (int i = 0; i < tests.length; i++) {
String[] s = removeHelper(tests[i]);
if (s != null)
System.out.println("Test \"" + tests[i] + "\" q=\"" + s[0] + "\" h=\"" + s[1] + "\"");
else
System.out.println("Test \"" + tests[i] + "\" no match");
}
}
****/
}

View File

@@ -3,12 +3,15 @@
*/
package net.i2p.i2ptunnel;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
@@ -60,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
@@ -71,33 +76,35 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
protected final List<String> _proxyList;
protected final static byte[] ERR_NO_OUTPROXY =
("HTTP/1.1 503 Service Unavailable\r\n"+
protected final static String ERR_NO_OUTPROXY =
"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 "+
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel")
.getBytes();
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel";
protected final static byte[] ERR_DESTINATION_UNKNOWN =
("HTTP/1.1 503 Service Unavailable\r\n" +
protected final static String ERR_DESTINATION_UNKNOWN =
"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 " +
"wrong BASE64 I2P Destination or the link you are following is " +
"bad. The host (or the WWW proxy, if you're using one) could also " +
"be temporarily offline. You may want to <b>retry</b>. " +
"Could not find the following Destination:<BR><BR><div>").getBytes();
"Could not find the following Destination:<BR><BR><div>";
protected final static byte[] SUCCESS_RESPONSE =
("HTTP/1.1 200 Connection Established\r\n"+
protected final static String SUCCESS_RESPONSE =
"HTTP/1.1 200 Connection Established\r\n"+
"Proxy-agent: I2P\r\n"+
"\r\n")
.getBytes();
"\r\n";
private final byte[] _proxyNonce;
private final ConcurrentHashMap<String, NonceInfo> _nonces;
@@ -214,11 +221,14 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
// see TunnelController.setSessionOptions()
String proxies = props.getProperty("proxyList");
if (proxies != null) {
StringTokenizer tok = new StringTokenizer(proxies, ", ");
StringTokenizer tok = new StringTokenizer(proxies, ",; \r\n\t");
synchronized(_proxyList) {
_proxyList.clear();
while (tok.hasMoreTokens())
_proxyList.add(tok.nextToken().trim());
while (tok.hasMoreTokens()) {
String p = tok.nextToken().trim();
if (p.length() > 0)
_proxyList.add(p);
}
}
} else {
synchronized(_proxyList) {
@@ -484,7 +494,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
* @return non-null
* @since 0.9.4 moved from I2PTunnelHTTPClient
*/
protected byte[] getErrorPage(String base, byte[] backup) {
protected String getErrorPage(String base, String backup) {
return getErrorPage(_context, base, backup);
}
@@ -499,7 +509,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
* @return non-null
* @since 0.9.4 moved from I2PTunnelHTTPClient
*/
protected static byte[] getErrorPage(I2PAppContext ctx, String base, byte[] backup) {
protected static String getErrorPage(I2PAppContext ctx, String base, String backup) {
File errorDir = new File(ctx.getBaseDir(), "docs");
File file = new File(errorDir, base + "-header.ht");
try {
@@ -515,7 +525,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
/**
* @since 0.9.4 moved from I2PTunnelHTTPClient
*/
private static byte[] readFile(I2PAppContext ctx, File file) throws IOException {
private static String readFile(I2PAppContext ctx, File file) throws IOException {
Reader reader = null;
char[] buf = new char[512];
StringBuilder out = new StringBuilder(2048);
@@ -525,7 +535,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
while((len = reader.read(buf)) > 0) {
out.append(buf, 0, len);
}
return out.toString().getBytes("UTF-8");
return out.toString();
} finally {
try {
if(reader != null)
@@ -578,7 +588,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
boolean usingWWWProxy, String wwwProxy, long requestId) {
if (out == null)
return;
byte[] header;
String header;
if (usingWWWProxy)
header = getErrorPage(I2PAppContext.getGlobalContext(), "dnfp", ERR_DESTINATION_UNKNOWN);
else
@@ -607,10 +617,12 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
error = usingWWWProxy ? "nolsp" : "nols";
} else if (status == MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION) {
error = usingWWWProxy ? "encp" : "enc";
} else if (status == I2PSocketException.STATUS_CONNECTION_RESET) {
error = usingWWWProxy ? "resetp" : "reset";
} else {
error = usingWWWProxy ? "dnfp" : "dnf";
}
byte[] header = getErrorPage(error, ERR_DESTINATION_UNKNOWN);
String header = getErrorPage(error, ERR_DESTINATION_UNKNOWN);
String message = ise != null ? ise.getLocalizedMessage() : "unknown error";
try {
writeErrorMessage(header, message, out, targetRequest, usingWWWProxy, wwwProxy);
@@ -621,7 +633,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
* No jump servers or extra message
* @since 0.9.14
*/
protected void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
protected void writeErrorMessage(String errMessage, OutputStream out, String targetRequest,
boolean usingWWWProxy, String wwwProxy) throws IOException {
writeErrorMessage(errMessage, null, out, targetRequest, usingWWWProxy, wwwProxy, null);
}
@@ -631,17 +643,17 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
* @param jumpServers comma- or space-separated list, or null
* @since 0.9.14 moved from subclasses
*/
protected void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
protected void writeErrorMessage(String errMessage, OutputStream out, String targetRequest,
boolean usingWWWProxy, String wwwProxy, String jumpServers) throws IOException {
writeErrorMessage(errMessage, null, out, targetRequest, usingWWWProxy, wwwProxy, jumpServers);
}
/**
* No jump servers
* @param extraMessage extra message
* @param extraMessage extra message or null, will be HTML-escaped
* @since 0.9.14
*/
protected void writeErrorMessage(byte[] errMessage, String extraMessage,
protected void writeErrorMessage(String errMessage, String extraMessage,
OutputStream out, String targetRequest,
boolean usingWWWProxy, String wwwProxy) throws IOException {
writeErrorMessage(errMessage, extraMessage, out, targetRequest, usingWWWProxy, wwwProxy, null);
@@ -649,30 +661,34 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
/**
* @param jumpServers comma- or space-separated list, or null
* @param extraMessage extra message
* @param extraMessage extra message or null, will be HTML-escaped
* @since 0.9.14
*/
protected void writeErrorMessage(byte[] errMessage, String extraMessage,
OutputStream out, String targetRequest,
protected void writeErrorMessage(String errMessage, String extraMessage,
OutputStream outs, String targetRequest,
boolean usingWWWProxy, String wwwProxy,
String jumpServers) throws IOException {
if (out == null)
if (outs == null)
return;
Writer out = new BufferedWriter(new OutputStreamWriter(outs, "UTF-8"));
out.write(errMessage);
if (targetRequest != null) {
String uri = targetRequest.replace("&", "&amp;");
out.write("<a href=\"".getBytes());
out.write(uri.getBytes());
out.write("\">".getBytes());
out.write(uri.getBytes());
out.write("</a>".getBytes());
String uri = DataHelper.escapeHTML(targetRequest);
out.write("<a href=\"");
out.write(uri);
out.write("\">");
if (targetRequest.length() > 80)
out.write(DataHelper.escapeHTML(targetRequest.substring(0, 75)) + "&hellip;");
else
out.write(uri);
out.write("</a>");
if (usingWWWProxy) {
out.write(("<br><br><b>").getBytes());
out.write(_("HTTP Outproxy").getBytes("UTF-8"));
out.write((":</b> " + wwwProxy).getBytes());
out.write("<br><br><b>");
out.write(_("HTTP Outproxy"));
out.write(":</b> " + wwwProxy);
}
if (extraMessage != null) {
out.write(("<br><br><b>" + extraMessage + "</b>").getBytes());
out.write("<br><br><b>" + DataHelper.escapeHTML(extraMessage) + "</b>");
}
if (jumpServers != null && jumpServers.length() > 0) {
boolean first = true;
@@ -706,21 +722,23 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
if (first) {
first = false;
out.write("<br><br>".getBytes());
out.write(_("Click a link below to look for an address helper by using a \"jump\" service:").getBytes("UTF-8"));
out.write("<br>\n".getBytes());
out.write("<br><br><h3>");
out.write(_("Click a link below for an address helper from a jump service"));
out.write("</h3>\n");
} else {
out.write("<br>");
}
out.write("<br><a href=\"".getBytes());
out.write(jurl.getBytes());
out.write(uri.getBytes());
out.write("\">".getBytes());
out.write("<a href=\"");
out.write(jurl);
out.write(uri);
out.write("\">");
// Translators: parameter is a host name
out.write(_("{0} jump service", jumphost).getBytes());
out.write("</a>\n".getBytes());
out.write(_("{0} jump service", jumphost));
out.write("</a>\n");
}
}
}
out.write("</div>".getBytes());
out.write("</div>");
writeFooter(out);
}
@@ -731,12 +749,29 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
* @since 0.9.14 moved from I2PTunnelHTTPClient
*/
public static void writeFooter(OutputStream out) throws IOException {
out.write(getFooter().getBytes("UTF-8"));
out.flush();
}
/**
* Flushes.
*
* Public only for LocalHTTPServer, not for general use
* @since 0.9.19
*/
public static void writeFooter(Writer out) throws IOException {
out.write(getFooter());
out.flush();
}
private static String getFooter() {
// The css is hiding this div for now, but we'll keep it here anyway
// Tag the strings below for translation if we unhide it.
out.write("<div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes());
out.write(new Date().toString().getBytes());
out.write("</i></div></body></html>\n".getBytes());
out.flush();
StringBuilder buf = new StringBuilder(128);
buf.append("<div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br>Generated on: ")
.append(new Date().toString())
.append("</i></div></body></html>\n");
return buf.toString();
}
/**

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();
@@ -86,7 +89,8 @@ public class I2PTunnelHTTPClientRunner extends I2PTunnelRunner {
// ignore
}
t1.join(30*1000);
t2.join(30*1000);
// t2 = fromI2P now run inline
//t2.join(30*1000);
}
}

View File

@@ -4,6 +4,7 @@
package net.i2p.i2ptunnel;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -11,6 +12,7 @@ import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -63,14 +65,22 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
private static final String SERVER_HEADER = "Server";
private static final String X_POWERED_BY_HEADER = "X-Powered-By";
private static final String[] SERVER_SKIPHEADERS = {SERVER_HEADER, X_POWERED_BY_HEADER};
/** timeout for first request line */
private static final long HEADER_TIMEOUT = 15*1000;
/** total timeout for the request and all the headers */
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"+
@@ -78,12 +88,11 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
"\r\n"+
"<html><head><title>503 Service Unavailable</title></head>\n"+
"<body><h2>503 Service Unavailable</h2>\n" +
"<p>This I2P eepsite is unavailable. It may be down or undergoing maintenance.</p>\n" +
"</body></html>")
.getBytes();
"<p>This I2P website is unavailable. It may be down or undergoing maintenance.</p>\n" +
"</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"+
@@ -92,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"+
@@ -105,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);
@@ -126,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
@@ -203,16 +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
socket.setReadTimeout(HEADER_TIMEOUT);
InputStream in = socket.getInputStream();
StringBuilder command = new StringBuilder(128);
Map<String, List<String>> headers = readHeaders(in, 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();
@@ -220,12 +355,24 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
(headers.containsKey("X-Forwarded-For") ||
headers.containsKey("X-Forwarded-Server") ||
headers.containsKey("X-Forwarded-Host"))) {
if (_log.shouldLog(Log.WARN))
_log.warn("Refusing inproxy access: " + peerHash.toBase64());
if (_log.shouldLog(Log.WARN)) {
StringBuilder buf = new StringBuilder();
buf.append("Refusing inproxy access: ").append(peerHash.toBase64());
List<String> h = headers.get("X-Forwarded-For");
if (h != null)
buf.append(" from: ").append(h.get(0));
h = headers.get("X-Forwarded-Server");
if (h != null)
buf.append(" via: ").append(h.get(0));
h = headers.get("X-Forwarded-Host");
if (h != null)
buf.append(" for: ").append(h.get(0));
_log.warn(buf.toString());
}
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();
@@ -242,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();
@@ -302,20 +449,20 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Modified header: [" + modifiedHeader + "]");
Runnable t;
if (allowGZIP && useGZIP) {
I2PAppThread req = new I2PAppThread(
new CompressedRequestor(s, socket, modifiedHeader, getTunnel().getContext(), _log),
Thread.currentThread().getName()+".hc");
req.start();
t = new CompressedRequestor(s, socket, modifiedHeader, getTunnel().getContext(), _log);
} else {
Thread t = new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(),
t = new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(),
null, (I2PTunnelRunner.FailCallback) null);
t.start();
}
// run in the unlimited client pool
//t.start();
_clientExecutor.execute(t);
long afterHandle = getTunnel().getContext().clock().now();
long timeToHandle = afterHandle - afterAccept;
getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle, 0);
getTunnel().getContext().statManager().addRateData("i2ptunnel.httpserver.blockingHandleTime", timeToHandle);
if ( (timeToHandle > 1000) && (_log.shouldLog(Log.WARN)) )
_log.warn("Took a while to handle the request for " + remoteHost + ':' + remotePort +
" [" + timeToHandle +
@@ -327,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();
@@ -348,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();
@@ -423,7 +570,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
//Change headers to protect server identity
StringBuilder command = new StringBuilder(128);
Map<String, List<String>> headers = readHeaders(serverin, command,
Map<String, List<String>> headers = readHeaders(null, serverin, command,
SERVER_SKIPHEADERS, _ctx);
String modifiedHeaders = formatHeaders(headers, command);
compressedOut.write(modifiedHeaders.getBytes());
@@ -439,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))
@@ -619,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.
*/
@@ -659,49 +803,71 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
}
}
protected static Map<String, List<String>> readHeaders(InputStream in, StringBuilder command,
/**
* From I2P to server: socket non-null, in null.
* From server to I2P: socket null, in non-null.
*
* @param socket if null, use in as InputStream
* @param in if null, use socket.getInputStream() as InputStream
* @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 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
*/
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);
// slowloris / darkloris
long expire = ctx.clock().now() + TOTAL_HEADER_TIMEOUT;
boolean ok = DataHelper.readLine(in, command);
if (!ok) throw new IOException("EOF reached while reading the HTTP command [" + command.toString() + "]");
if (socket != null) {
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 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, 0);
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);
ok = DataHelper.readLine(in, buf);
if (!ok) throw new IOException("EOF reached before the end of the headers [" + buf.toString() + "]");
if (socket != null) {
readLine(socket, buf, expire - ctx.clock().now());
} else {
boolean ok = DataHelper.readLine(in, buf);
if (!ok)
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)
@@ -740,5 +906,77 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
}
}
}
/**
* Read a line teriminated by newline, with a total read timeout.
*
* Warning - strips \n but not \r
* Warning - 8KB line length limit as of 0.7.13, @throws IOException if exceeded
* Warning - not UTF-8
*
* @param buf output
* @param timeout throws SocketTimeoutException immediately if zero or negative
* @throws SocketTimeoutException if timeout is reached before newline
* @throws EOFException if EOF is reached before newline
* @throws LineTooLongException if too long
* @throws IOException on other errors in the underlying stream
* @since 0.9.19 modified from DataHelper
*/
private static void readLine(I2PSocket socket, StringBuilder buf, long timeout) throws IOException {
if (timeout <= 0)
throw new SocketTimeoutException();
long expires = System.currentTimeMillis() + timeout;
InputStream in = socket.getInputStream();
int c;
int i = 0;
socket.setReadTimeout(timeout);
while ( (c = in.read()) != -1) {
if (++i > MAX_LINE_LENGTH)
throw new LineTooLongException("Line too long - max " + MAX_LINE_LENGTH);
if (c == '\n')
break;
long newTimeout = expires - System.currentTimeMillis();
if (newTimeout <= 0)
throw new SocketTimeoutException();
buf.append((char)c);
if (newTimeout != timeout) {
timeout = newTimeout;
socket.setReadTimeout(timeout);
}
}
if (c == -1) {
if (System.currentTimeMillis() >= expires)
throw new SocketTimeoutException();
else
throw new EOFException();
}
}
/**
* @since 0.9.19
*/
private static class LineTooLongException extends IOException {
public LineTooLongException(String s) {
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");
}
@@ -136,8 +137,11 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase {
DCCHelper dcc = _dccEnabled ? new DCC(s.getLocalAddress().getAddress()) : null;
Thread in = new I2PAppThread(new IrcInboundFilter(s,i2ps, expectedPong, _log, dcc), "IRC Client " + _clientId + " in", true);
in.start();
Thread out = new I2PAppThread(new IrcOutboundFilter(s,i2ps, expectedPong, _log, dcc), "IRC Client " + _clientId + " out", true);
out.start();
//Thread out = new I2PAppThread(new IrcOutboundFilter(s,i2ps, expectedPong, _log, dcc), "IRC Client " + _clientId + " out", true);
Runnable out = new IrcOutboundFilter(s,i2ps, expectedPong, _log, dcc);
// we are called from an unlimited thread pool, so run inline
//out.start();
out.run();
} catch (Exception ex) {
// generally NoRouteToHostException
if (_log.shouldLog(Log.WARN))
@@ -194,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

@@ -1,17 +1,18 @@
package net.i2p.i2ptunnel;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Locale;
import java.util.Properties;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.crypto.SHA256Generator;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.data.Base32;
@@ -54,23 +55,44 @@ import net.i2p.util.Log;
* @author zzz
*/
public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
private final byte[] cloakKey; // 32 bytes of stuff to scramble the dest with
private final String hostname;
private final String method;
private final String webircPassword;
private final String webircSpoofIP;
public static final String PROP_METHOD="ircserver.method";
public static final String PROP_METHOD_DEFAULT="user";
public static final String PROP_CLOAK="ircserver.cloakKey";
public static final String PROP_WEBIRC_PASSWORD="ircserver.webircPassword";
public static final String PROP_WEBIRC_SPOOF_IP="ircserver.webircSpoofIP";
public static final String PROP_WEBIRC_SPOOF_IP_DEFAULT="127.0.0.1";
public static final String PROP_WEBIRC_SPOOF_IP="ircserver.webircSpoofIP";
public static final String PROP_WEBIRC_SPOOF_IP_DEFAULT="127.0.0.1";
public static final String PROP_HOSTNAME="ircserver.fakeHostname";
public static final String PROP_HOSTNAME_DEFAULT="%f.b32.i2p";
private static final long HEADER_TIMEOUT = 15*1000;
private static final long TOTAL_HEADER_TIMEOUT = 2 * HEADER_TIMEOUT;
private static final int MAX_LINE_LENGTH = 1024;
private final static byte[] ERR_UNAVAILABLE =
(":ircserver.i2p 499 you :" +
"This I2P IRC server is unvailable. It may be down or undergoing maintenance. " +
private final static String ERR_UNAVAILABLE =
":ircserver.i2p 499 you :" +
"This I2P IRC server is unavailable. It may be down or undergoing maintenance. " +
"Please try again later." +
"\r\n")
.getBytes();
"\r\n";
private final static String ERR_REGISTRATION =
":ircserver.i2p 499 you :" +
"Bad registration." +
"\r\n";
private final static String ERR_TIMEOUT =
":ircserver.i2p 499 you :" +
"Timeout registering." +
"\r\n";
private final static String ERR_EOF =
":ircserver.i2p 499 you :" +
"EOF while registering." +
"\r\n";
private static final String[] BAD_PROTOCOLS = {
"GET ", "HEAD ", "POST ", "GNUTELLA CONNECT", "\023BitTorrent protocol"
@@ -97,8 +119,8 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
// get the password for the webirc method
this.webircPassword = opts.getProperty(PROP_WEBIRC_PASSWORD);
// get the spoof IP for the webirc method
this.webircSpoofIP = opts.getProperty(PROP_WEBIRC_SPOOF_IP, PROP_WEBIRC_SPOOF_IP_DEFAULT);
// get the spoof IP for the webirc method
this.webircSpoofIP = opts.getProperty(PROP_WEBIRC_SPOOF_IP, PROP_WEBIRC_SPOOF_IP_DEFAULT);
// get the cloaking passphrase
String passphrase = opts.getProperty(PROP_CLOAK);
@@ -119,33 +141,66 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
_log.info("Incoming connection to '" + toString() + "' port " + socket.getLocalPort() +
" from: " + socket.getPeerDestination().calculateHash() + " port " + socket.getPort());
try {
String modifiedRegistration;
if(!this.method.equals("webirc")) {
// The headers _should_ be in the first packet, but
// may not be, depending on the client-side options
socket.setReadTimeout(HEADER_TIMEOUT);
InputStream in = socket.getInputStream();
modifiedRegistration = filterRegistration(in, cloakDest(socket.getPeerDestination()));
socket.setReadTimeout(readTimeout);
} else {
StringBuffer buf = new StringBuffer("WEBIRC ");
buf.append(this.webircPassword);
buf.append(" cgiirc ");
buf.append(cloakDest(socket.getPeerDestination()));
buf.append(' ');
buf.append(this.webircSpoofIP);
buf.append("\r\n");
modifiedRegistration = buf.toString();
}
String modifiedRegistration;
if(!this.method.equals("webirc")) {
// The headers _should_ be in the first packet, but
// may not be, depending on the client-side options
modifiedRegistration = filterRegistration(socket, cloakDest(socket.getPeerDestination()));
socket.setReadTimeout(readTimeout);
} else {
StringBuffer buf = new StringBuffer("WEBIRC ");
buf.append(this.webircPassword);
buf.append(" cgiirc ");
buf.append(cloakDest(socket.getPeerDestination()));
buf.append(' ');
buf.append(this.webircSpoofIP);
buf.append("\r\n");
modifiedRegistration = buf.toString();
}
Socket s = getSocket(socket.getPeerDestination().calculateHash(), socket.getLocalPort());
Thread t = new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(),
null, (I2PTunnelRunner.FailCallback) null);
t.start();
// run in the unlimited client pool
//t.start();
_clientExecutor.execute(t);
} catch (RegistrationException ex) {
try {
// Send a response so the user doesn't just see a disconnect
// and blame his router or the network.
socket.getOutputStream().write(ERR_REGISTRATION.getBytes("ISO-8859-1"));
} catch (IOException ioe) {
} finally {
try { socket.close(); } catch (IOException ioe) {}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new IRC Connection", ex);
} catch (EOFException ex) {
try {
// Send a response so the user doesn't just see a disconnect
// and blame his router or the network.
socket.getOutputStream().write(ERR_EOF.getBytes("ISO-8859-1"));
} catch (IOException ioe) {
} finally {
try { socket.close(); } catch (IOException ioe) {}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new IRC Connection", ex);
} catch (SocketTimeoutException ex) {
try {
// Send a response so the user doesn't just see a disconnect
// and blame his router or the network.
socket.getOutputStream().write(ERR_TIMEOUT.getBytes("ISO-8859-1"));
} catch (IOException ioe) {
} finally {
try { socket.close(); } catch (IOException ioe) {}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new IRC Connection", ex);
} catch (SocketException ex) {
try {
// Send a response so the user doesn't just see a disconnect
// and blame his router or the network.
socket.getOutputStream().write(ERR_UNAVAILABLE);
socket.getOutputStream().write(ERR_UNAVAILABLE.getBytes("ISO-8859-1"));
} catch (IOException ioe) {}
try {
socket.close();
@@ -189,27 +244,35 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
return this.hostname.replace("%f", hf).replace("%c", hc);
}
/** keep reading until we see USER or SERVER */
private static String filterRegistration(InputStream in, String newHostname) throws IOException {
/**
* Keep reading until we see USER or SERVER.
* This modifies the socket readTimeout, caller must save and restore.
*
* @throws SocketTimeoutException if timeout is reached before newline
* @throws EOFException if EOF is reached before newline
* @throws RegistrationException if line too long
* @throws IOException on other errors in the underlying stream
*/
private static String filterRegistration(I2PSocket socket, String newHostname) throws IOException {
StringBuilder buf = new StringBuilder(128);
int lineCount = 0;
// slowloris / darkloris
long expire = System.currentTimeMillis() + TOTAL_HEADER_TIMEOUT;
while (true) {
String s = DataHelper.readLine(in);
String s = readLine(socket, expire - System.currentTimeMillis());
if (s == null)
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 (lineCount == 0) {
for (int i = 0; i < BAD_PROTOCOLS.length; i++) {
if (s.startsWith(BAD_PROTOCOLS[i]))
throw new IOException("Bad protocol " + BAD_PROTOCOLS[i]);
throw new RegistrationException("Bad protocol " + BAD_PROTOCOLS[i]);
}
}
if (++lineCount > 10)
throw new IOException("Too many lines before USER or SERVER, giving up");
throw new RegistrationException("Too many lines before USER or SERVER, giving up");
if (System.currentTimeMillis() > expire)
throw new IOException("Headers took too long [" + buf.toString() + "]");
throw new SocketTimeoutException("Headers took too long");
s = s.trim();
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Got line: " + s);
@@ -223,12 +286,12 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
idx++;
command = field[idx++].toUpperCase(Locale.US);
} catch (IndexOutOfBoundsException ioobe) {
throw new IOException("Dropping defective message: [" + s + ']');
throw new RegistrationException("Dropping defective message: [" + s + ']');
}
if ("USER".equals(command)) {
if (field.length < idx + 4)
throw new IOException("Too few parameters in USER message: " + s);
throw new RegistrationException("Too few parameters in USER message: " + s);
// USER zzz1 hostname localhost :zzz
// =>
// USER zzz1 abcd1234.i2p localhost :zzz
@@ -247,9 +310,58 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
return buf.toString();
}
private final byte[] cloakKey; // 32 bytes of stuff to scramble the dest with
private final String hostname;
private final String method;
private final String webircPassword;
private final String webircSpoofIP;
/**
* Read a line teriminated by newline, with a total read timeout.
*
* Warning - strips \n but not \r
* Warning - 8KB line length limit as of 0.7.13, @throws IOException if exceeded
* Warning - not UTF-8
*
* @param timeout throws SocketTimeoutException immediately if zero or negative
* @throws SocketTimeoutException if timeout is reached before newline
* @throws EOFException if EOF is reached before newline
* @throws RegistrationException if line too long
* @throws IOException on other errors in the underlying stream
* @since 0.9.19 modified from DataHelper and I2PTunnelHTTPServer
*/
private static String readLine(I2PSocket socket, long timeout) throws IOException {
StringBuilder buf = new StringBuilder(128);
if (timeout <= 0)
throw new SocketTimeoutException();
long expires = System.currentTimeMillis() + timeout;
InputStream in = socket.getInputStream();
int c;
int i = 0;
socket.setReadTimeout(timeout);
while ( (c = in.read()) != -1) {
if (++i > MAX_LINE_LENGTH)
throw new RegistrationException("Line too long - max " + MAX_LINE_LENGTH);
if (c == '\n')
break;
long newTimeout = expires - System.currentTimeMillis();
if (newTimeout <= 0)
throw new SocketTimeoutException();
buf.append((char)c);
if (newTimeout != timeout) {
timeout = newTimeout;
socket.setReadTimeout(timeout);
}
}
if (c == -1) {
if (System.currentTimeMillis() >= expires)
throw new SocketTimeoutException();
else
throw new EOFException();
}
return buf.toString();
}
/**
* @since 0.9.19
*/
private static class RegistrationException extends IOException {
public RegistrationException(String s) {
super(s);
}
}
}

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

@@ -62,8 +62,6 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr
private long totalSent;
private long totalReceived;
private static final AtomicLong __forwarderId = new AtomicLong();
/**
* For use in new constructor
* @since 0.9.14
@@ -200,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
@@ -208,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
@@ -268,9 +269,10 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr
in = new BufferedInputStream(in, 2*NETWORK_BUFFER_SIZE);
StreamForwarder toI2P = new StreamForwarder(in, i2pout, true);
StreamForwarder fromI2P = new StreamForwarder(i2pin, out, false);
// TODO can we run one of these inline and save a thread?
toI2P.start();
fromI2P.start();
// We are already a thread, so run the second one inline
//fromI2P.start();
fromI2P.run();
synchronized (finishLock) {
while (!finished) {
finishLock.wait();
@@ -384,7 +386,8 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr
// ignore
}
t1.join(30*1000);
t2.join(30*1000);
// t2 = fromI2P now run inline
//t2.join(30*1000);
}
/**
@@ -426,7 +429,7 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr
_toI2P = toI2P;
direction = (toI2P ? "toI2P" : "fromI2P");
_cache = ByteCache.getInstance(32, NETWORK_BUFFER_SIZE);
setName("StreamForwarder " + _runnerId + '.' + __forwarderId.incrementAndGet());
setName("StreamForwarder " + _runnerId + '.' + direction);
}
@Override
@@ -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

@@ -80,6 +80,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
protected I2PTunnelTask task;
protected boolean bidir;
private ThreadPoolExecutor _executor;
protected volatile ThreadPoolExecutor _clientExecutor;
private final Map<Integer, InetSocketAddress> _socketMap = new ConcurrentHashMap<Integer, InetSocketAddress>(4);
/** unused? port should always be specified */
@@ -470,6 +471,16 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
if (_usePool) {
_executor = new CustomThreadPoolExecutor(getHandlerCount(), "ServerHandler pool " + remoteHost + ':' + remotePort);
}
TunnelControllerGroup tcg = TunnelControllerGroup.getInstance();
if (tcg != null) {
_clientExecutor = tcg.getClientExecutor();
} 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.
// Never shut down.
_clientExecutor = new TunnelControllerGroup.CustomThreadPoolExecutor();
}
while (open) {
try {
I2PServerSocket ci2pss = i2pss;
@@ -559,10 +570,25 @@ 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);
}
}
}
/**
* This is run in a thread from a limited-size thread pool via Handler.run(),
* except for a standard server (this class, no extension, as determined in getUsePool()),
* it is run directly in the acceptor thread (see run()).
*
* In either case, this method and any overrides must spawn a thread and return quickly.
* If blocking while reading the headers (as in HTTP and IRC), the thread pool
* may be exhausted.
*
* See PROP_USE_POOL, DEFAULT_USE_POOL, PROP_HANDLER_COUNT, DEFAULT_HANDLER_COUNT
*/
protected void blockingHandle(I2PSocket socket) {
if (_log.shouldLog(Log.INFO))
_log.info("Incoming connection to '" + toString() + "' port " + socket.getLocalPort() +
@@ -577,7 +603,9 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
afterSocket = getTunnel().getContext().clock().now();
Thread t = new I2PTunnelRunner(s, socket, slock, null, null,
null, (I2PTunnelRunner.FailCallback) null);
t.start();
// run in the unlimited client pool
//t.start();
_clientExecutor.execute(t);
long afterHandle = getTunnel().getContext().clock().now();
long timeToHandle = afterHandle - afterAccept;

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

@@ -42,8 +42,18 @@ public class TunnelController implements Logging {
private final I2PTunnel _tunnel;
private final List<String> _messages;
private List<I2PSession> _sessions;
private boolean _running;
private boolean _starting;
private volatile TunnelState _state;
/** @since 0.9.19 */
private enum TunnelState {
START_ON_LOAD,
STARTING,
RUNNING,
STOPPING,
STOPPED,
DESTROYING,
DESTROYED,
}
public static final String KEY_BACKUP_DIR = "i2ptunnel-keyBackup";
@@ -104,6 +114,8 @@ public class TunnelController implements Logging {
* the prefix should be used (and, in turn, that prefix should be stripped off
* before being interpreted by this controller)
*
* Defaults in config properties are not recommended, they may or may not be honored.
*
* @param config original key=value mapping non-null
* @param prefix beginning of key values that are relevant to this tunnel
*/
@@ -112,6 +124,7 @@ public class TunnelController implements Logging {
}
/**
* Defaults in config properties are not recommended, they may or may not be honored.
*
* @param config original key=value mapping non-null
* @param prefix beginning of key values that are relevant to this tunnel
@@ -124,11 +137,10 @@ public class TunnelController implements Logging {
_log = I2PAppContext.getGlobalContext().logManager().getLog(TunnelController.class);
setConfig(config, prefix);
_messages = new ArrayList<String>(4);
_running = false;
boolean keyOK = true;
if (createKey && (getType().endsWith("server") || getPersistentClientKey()))
keyOK = createPrivateKey();
_starting = keyOK && getStartOnLoad();
_state = keyOK && getStartOnLoad() ? TunnelState.START_ON_LOAD : TunnelState.STOPPED;
}
/**
@@ -193,9 +205,11 @@ public class TunnelController implements Logging {
}
public void startTunnelBackground() {
if (_running) return;
_starting = true;
new I2PAppThread(new Runnable() { public void run() { startTunnel(); } }).start();
synchronized (this) {
if (_state != TunnelState.STOPPED && _state != TunnelState.START_ON_LOAD)
return;
}
new I2PAppThread(new Runnable() { public void run() { startTunnel(); } }, "Tunnel Starter " + getName()).start();
}
/**
@@ -203,7 +217,17 @@ public class TunnelController implements Logging {
*
*/
public void startTunnel() {
_starting = true;
synchronized (this) {
if (_state != TunnelState.STOPPED && _state != TunnelState.START_ON_LOAD) {
if (_state == TunnelState.RUNNING) {
if (_log.shouldLog(Log.INFO))
_log.info("Already running");
log("Tunnel " + getName() + " is already running");
}
return;
}
changeState(TunnelState.STARTING);
}
try {
doStartTunnel();
} catch (Exception e) {
@@ -213,21 +237,20 @@ public class TunnelController implements Logging {
acquire();
stopTunnel();
}
_starting = false;
}
/**
* @throws IllegalArgumentException via methods in I2PTunnel
*/
private void doStartTunnel() {
if (_running) {
if (_log.shouldLog(Log.INFO))
_log.info("Already running");
log("Tunnel " + getName() + " is already running");
return;
synchronized (this) {
if (_state != TunnelState.STARTING)
return;
}
String type = getType();
if ( (type == null) || (type.length() <= 0) ) {
changeState(TunnelState.STOPPED);
if (_log.shouldLog(Log.ERROR))
_log.error("Cannot start the tunnel - no type specified");
return;
@@ -237,6 +260,7 @@ public class TunnelController implements Logging {
if (type.endsWith("server") || getPersistentClientKey()) {
boolean ok = createPrivateKey();
if (!ok) {
changeState(TunnelState.STOPPED);
log("Failed to start tunnel " + getName() + " as the private key file could not be created");
return;
}
@@ -268,12 +292,13 @@ public class TunnelController implements Logging {
} else if (TYPE_STREAMR_SERVER.equals(type)) {
startStreamrServer();
} else {
changeState(TunnelState.STOPPED);
if (_log.shouldLog(Log.ERROR))
_log.error("Cannot start tunnel - unknown type [" + type + "]");
return;
}
acquire();
_running = true;
changeState(TunnelState.RUNNING);
}
private void startHttpClient() {
@@ -425,7 +450,7 @@ public class TunnelController implements Logging {
// We use _sessions AND the tunnel sessions as
// _sessions will be null for delay-open tunnels - see acquire().
// We want the current sessions.
Set<I2PSession> sessions = new HashSet(_tunnel.getSessions());
Set<I2PSession> sessions = new HashSet<I2PSession>(_tunnel.getSessions());
if (_sessions != null)
sessions.addAll(_sessions);
return sessions;
@@ -485,6 +510,7 @@ public class TunnelController implements Logging {
/**
* These are the ones stored with a prefix of "option."
* Defaults in config properties are not honored.
*
* @return keys with the "option." prefix stripped, non-null
* @since 0.9.1 Much better than getClientOptions()
@@ -554,12 +580,17 @@ public class TunnelController implements Logging {
* and it may have timer threads that continue running.
*/
public void stopTunnel() {
synchronized (this) {
if (_state != TunnelState.STARTING && _state != TunnelState.RUNNING)
return;
changeState(TunnelState.STOPPING);
}
// I2PTunnel removes the session in close(),
// so save the sessions to pass to release() and TCG
Collection<I2PSession> sessions = getAllSessions();
_tunnel.runClose(new String[] { "forced", "all" }, this);
release(sessions);
_running = false;
changeState(TunnelState.STOPPED);
}
/**
@@ -569,12 +600,17 @@ public class TunnelController implements Logging {
* @since 0.9.17
*/
public void destroyTunnel() {
synchronized (this) {
if (_state != TunnelState.RUNNING)
return;
changeState(TunnelState.DESTROYING);
}
// I2PTunnel removes the session in close(),
// so save the sessions to pass to release() and TCG
Collection<I2PSession> sessions = getAllSessions();
_tunnel.runClose(new String[] { "destroy", "all" }, this);
release(sessions);
_running = false;
changeState(TunnelState.DESTROYED);
}
public void restartTunnel() {
@@ -615,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());
}
@@ -626,26 +662,29 @@ public class TunnelController implements Logging {
// tell i2ptunnel, who will tell the TunnelTask, who will tell the SocketManager
setSessionOptions();
if (_running) {
Collection<I2PSession> sessions = getAllSessions();
if (sessions.isEmpty()) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Running but no sessions to update");
}
for (I2PSession s : sessions) {
// tell the router via the session
if (!s.isClosed()) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Session is open, updating: " + s);
s.updateOptions(_tunnel.getClientOptions());
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Session is closed, not updating: " + s);
synchronized (this) {
if (_state != TunnelState.RUNNING) {
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Not running, not updating sessions");
}
return;
}
} else {
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Not running, not updating sessions");
}
// Running, so check sessions
Collection<I2PSession> sessions = getAllSessions();
if (sessions.isEmpty()) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Running but no sessions to update");
}
for (I2PSession s : sessions) {
// tell the router via the session
if (!s.isClosed()) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Session is open, updating: " + s);
s.updateOptions(_tunnel.getClientOptions());
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Session is closed, not updating: " + s);
}
}
}
@@ -794,19 +833,27 @@ public class TunnelController implements Logging {
return null;
}
public boolean getIsRunning() { return _running; }
public boolean getIsStarting() { return _starting; }
public boolean getIsRunning() { return _state == TunnelState.RUNNING; }
public boolean getIsStarting() { return _state == TunnelState.START_ON_LOAD || _state == TunnelState.STARTING; }
/** if running but no open sessions, we are in standby */
public boolean getIsStandby() {
if (!_running)
return false;
synchronized (this) {
if (_state != TunnelState.RUNNING)
return false;
}
for (I2PSession sess : _tunnel.getSessions()) {
if (!sess.isClosed())
return false;
}
return true;
}
/** @since 0.9.19 */
private synchronized void changeState(TunnelState state) {
_state = state;
}
/**
* A text description of the tunnel.
@@ -927,7 +974,7 @@ public class TunnelController implements Logging {
*
*/
public void log(String s) {
synchronized (this) {
synchronized (_messages) {
_messages.add(s);
while (_messages.size() > 10)
_messages.remove(0);
@@ -942,8 +989,8 @@ public class TunnelController implements Logging {
* @return list of messages pulled off (each is a String, earliest first)
*/
public List<String> clearMessages() {
List<String> rv = null;
synchronized (this) {
List<String> rv;
synchronized (_messages) {
rv = new ArrayList<String>(_messages);
_messages.clear();
}
@@ -955,6 +1002,6 @@ public class TunnelController implements Logging {
*/
@Override
public String toString() {
return "TC " + getType() + ' ' + getName() + " for " + _tunnel;
return "TC " + getType() + ' ' + getName() + " for " + _tunnel + ' ' + _state;
}
}

View File

@@ -9,6 +9,14 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import net.i2p.I2PAppContext;
import net.i2p.app.*;
@@ -36,6 +44,9 @@ public class TunnelControllerGroup implements ClientApp {
static final String DEFAULT_CONFIG_FILE = "i2ptunnel.config";
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";
@@ -48,6 +59,21 @@ public class TunnelControllerGroup implements ClientApp {
*/
private final Map<I2PSession, Set<TunnelController>> _sessions;
/**
* We keep a pool of socket handlers for all clients,
* as there is no need for isolation on the client side.
* Extending classes may use it for other purposes.
*
* May also be used by servers, carefully,
* as there is no limit on threads.
*/
private ThreadPoolExecutor _executor;
private static final AtomicLong _executorThreadCount = new AtomicLong();
private final Object _executorLock = new Object();
/** how long to wait before dropping an idle thread */
private static final long HANDLER_KEEPALIVE_MS = 2*60*1000;
/**
* In I2PAppContext will instantiate if necessary and always return non-null.
* As of 0.9.4, when in RouterContext, will return null (except in Android)
@@ -61,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;
@@ -75,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) {
@@ -83,6 +111,7 @@ public class TunnelControllerGroup implements ClientApp {
_mgr = mgr;
_log = _context.logManager().getLog(TunnelControllerGroup.class);
_controllers = new ArrayList<TunnelController>();
_controllersLock = new ReentrantReadWriteLock(true);
if (args == null || args.length <= 0)
_configFile = DEFAULT_CONFIG_FILE;
else if (args.length == 1)
@@ -121,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
@@ -206,46 +248,80 @@ public class TunnelControllerGroup implements ClientApp {
if (_instance == this)
_instance = null;
}
/// fixme static
I2PTunnelClientBase.killClientExecutor();
killClientExecutor();
changeState(STOPPED);
}
/**
* 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);
Properties cfg = loadConfig(configFile);
int i = 0;
while (true) {
String type = cfg.getProperty("tunnel." + i + ".type");
if (type == null)
break;
TunnelController controller = new TunnelController(cfg, "tunnel." + i + ".");
_controllers.add(controller);
i++;
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)
break;
TunnelController controller = new TunnelController(cfg, "tunnel." + i + ".");
_controllers.add(controller);
i++;
}
} 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);
}
private class StartControllers implements Runnable {
public void run() {
synchronized(TunnelControllerGroup.this) {
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
if (controller.getStartOnLoad())
controller.startTunnel();
_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.startTunnelBackground();
}
} finally {
_controllersLock.readLock().unlock();
}
}
}
@@ -260,6 +336,7 @@ public class TunnelControllerGroup implements ClientApp {
public synchronized void reloadControllers() {
unloadControllers();
loadControllers(_configFile);
startControllers();
}
/**
@@ -268,19 +345,40 @@ public class TunnelControllerGroup implements ClientApp {
*
*/
public synchronized void unloadControllers() {
destroyAllControllers();
_controllers.clear();
synchronized (_controllersLoadedLock) {
if (!_controllersLoaded)
return;
}
_controllersLock.writeLock().lock();
try {
destroyAllControllers();
_controllers.clear();
} finally {
_controllersLock.writeLock().unlock();
}
synchronized (_controllersLoadedLock) {
_controllersLoaded = false;
}
if (_log.shouldLog(Log.INFO))
_log.info("All controllers stopped and unloaded");
}
/**
* Add the given tunnel to the set of known controllers (but dont add it to
* a config file or start it or anything)
*
*/
public synchronized void addController(TunnelController controller) { _controllers.add(controller); }
public synchronized void addController(TunnelController controller) {
_controllersLock.writeLock().lock();
try {
_controllers.add(controller);
} finally {
_controllersLock.writeLock().unlock();
}
}
/**
* Stop and remove the given tunnel
*
@@ -290,7 +388,12 @@ public class TunnelControllerGroup implements ClientApp {
if (controller == null) return new ArrayList<String>();
controller.stopTunnel();
List<String> msgs = controller.clearMessages();
_controllers.remove(controller);
_controllersLock.writeLock().lock();
try {
_controllers.remove(controller);
} finally {
_controllersLock.writeLock().unlock();
}
msgs.add("Tunnel " + controller.getName() + " removed");
return msgs;
}
@@ -302,13 +405,18 @@ public class TunnelControllerGroup implements ClientApp {
*/
public synchronized List<String> stopAllControllers() {
List<String> msgs = new ArrayList<String>();
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
controller.stopTunnel();
msgs.addAll(controller.clearMessages());
_controllersLock.readLock().lock();
try {
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
controller.stopTunnel();
msgs.addAll(controller.clearMessages());
}
if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers stopped");
} finally {
_controllersLock.readLock().unlock();
}
if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers stopped");
return msgs;
}
@@ -334,14 +442,19 @@ public class TunnelControllerGroup implements ClientApp {
*/
public synchronized List<String> startAllControllers() {
List<String> msgs = new ArrayList<String>();
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
controller.startTunnelBackground();
msgs.addAll(controller.clearMessages());
}
_controllersLock.readLock().lock();
try {
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
controller.startTunnelBackground();
msgs.addAll(controller.clearMessages());
}
if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers started");
if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers started");
} finally {
_controllersLock.readLock().unlock();
}
return msgs;
}
@@ -352,13 +465,18 @@ public class TunnelControllerGroup implements ClientApp {
*/
public synchronized List<String> restartAllControllers() {
List<String> msgs = new ArrayList<String>();
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
controller.restartTunnel();
msgs.addAll(controller.clearMessages());
_controllersLock.readLock().lock();
try {
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
controller.restartTunnel();
msgs.addAll(controller.clearMessages());
}
if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers restarted");
} finally {
_controllersLock.readLock().unlock();
}
if (_log.shouldLog(Log.INFO))
_log.info(_controllers.size() + " controllers restarted");
return msgs;
}
@@ -367,11 +485,16 @@ public class TunnelControllerGroup implements ClientApp {
*
* @return list of messages the tunnels have generated
*/
public synchronized List<String> clearAllMessages() {
public List<String> clearAllMessages() {
List<String> msgs = new ArrayList<String>();
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
msgs.addAll(controller.clearMessages());
_controllersLock.readLock().lock();
try {
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
msgs.addAll(controller.clearMessages());
}
} finally {
_controllersLock.readLock().unlock();
}
return msgs;
}
@@ -398,10 +521,15 @@ public class TunnelControllerGroup implements ClientApp {
parent.mkdirs();
Properties map = new OrderedProperties();
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
Properties cur = controller.getConfig("tunnel." + i + ".");
map.putAll(cur);
_controllersLock.readLock().lock();
try {
for (int i = 0; i < _controllers.size(); i++) {
TunnelController controller = _controllers.get(i);
Properties cur = controller.getConfig("tunnel." + i + ".");
map.putAll(cur);
}
} finally {
_controllersLock.readLock().unlock();
}
DataHelper.storeProps(map, cfgFile);
@@ -435,12 +563,26 @@ 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 synchronized List<TunnelController> getControllers() {
return new ArrayList<TunnelController>(_controllers);
public List<TunnelController> getControllers() {
synchronized (_controllersLoadedLock) {
if (!_controllersLoaded)
loadControllers(_configFile);
}
_controllersLock.readLock().lock();
try {
return new ArrayList<TunnelController>(_controllers);
} finally {
_controllersLock.readLock().unlock();
}
}
@@ -500,4 +642,59 @@ public class TunnelControllerGroup implements ClientApp {
}
}
}
/**
* @return non-null
* @since 0.8.8 Moved from I2PTunnelClientBase in 0.9.18
*/
ThreadPoolExecutor getClientExecutor() {
synchronized (_executorLock) {
if (_executor == null)
_executor = new CustomThreadPoolExecutor();
}
return _executor;
}
/**
* @since 0.8.8 Moved from I2PTunnelClientBase in 0.9.18
*/
private void killClientExecutor() {
synchronized (_executorLock) {
if (_executor != null) {
_executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
_executor.shutdownNow();
_executor = null;
}
}
// kill the shared client, so that on restart in android
// we won't latch onto the old one
I2PTunnelClientBase.killSharedClient();
}
/**
* Not really needed for now but in case we want to add some hooks like afterExecute().
* Package private for fallback in case TCG.getInstance() is null, never instantiated
* but a plugin still needs it... should be rare.
*
* @since 0.9.18 Moved from I2PTunnelClientBase
*/
static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
public CustomThreadPoolExecutor() {
super(0, Integer.MAX_VALUE, HANDLER_KEEPALIVE_MS, TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>(), new CustomThreadFactory());
}
}
/**
* Just to set the name and set Daemon
* @since 0.9.18 Moved from I2PTunnelClientBase
*/
private static class CustomThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
Thread rv = Executors.defaultThreadFactory().newThread(r);
rv.setName("I2PTunnel Client Runner " + _executorThreadCount.incrementAndGet());
rv.setDaemon(true);
return rv;
}
}
}

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();
}
/**
@@ -76,7 +77,9 @@ public class I2PTunnelDCCClient extends I2PTunnelClientBase {
try {
i2ps = createI2PSocket(dest, opts);
Thread t = new Runner(s, i2ps);
t.start();
// we are called from an unlimited thread pool, so run inline
//t.start();
t.run();
} catch (Exception ex) {
_log.error("Could not make DCC connection to " + _dest + ':' + _remotePort, ex);
closeSocket(s);

View File

@@ -111,7 +111,9 @@ public class I2PTunnelDCCServer extends I2PTunnelServer {
_sockList.add(socket);
Thread t = new I2PTunnelRunner(s, socket, slock, null, null, _sockList,
(I2PTunnelRunner.FailCallback) null);
t.start();
// run in the unlimited client pool
//t.start();
_clientExecutor.execute(t);
local.socket = socket;
local.expire = getTunnel().getContext().clock().now() + OUTBOUND_EXPIRE;
_active.put(Integer.valueOf(myPort), local);

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

@@ -0,0 +1,7 @@
<html>
<body>
<p>
Filters for the IRC client tunnel, and DCC handlers.
</p>
</body>
</html>

View File

@@ -33,19 +33,30 @@ import net.i2p.util.Translate;
*/
public abstract class LocalHTTPServer {
private final static byte[] ERR_404 =
("HTTP/1.1 404 Not Found\r\n"+
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")
.getBytes();
"HTTP Proxy local file not found";
private final static byte[] ERR_ADD =
("HTTP/1.1 409 Bad\r\n"+
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")
.getBytes();
"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.
@@ -69,14 +80,13 @@ public abstract class LocalHTTPServer {
* @param targetRequest decoded path only, non-null
* @param query raw (encoded), may be null
*/
public static void serveLocalFile(OutputStream out, String method, String targetRequest, String query, String proxyNonce) {
public static void serveLocalFile(OutputStream out, String method, String targetRequest,
String query, String proxyNonce) throws IOException {
//System.err.println("targetRequest: \"" + targetRequest + "\"");
// a home page message for the curious...
if (targetRequest.equals("/")) {
try {
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());
out.flush();
} catch (IOException ioe) {}
out.write(OK.getBytes("UTF-8"));
out.flush();
return;
}
if ((method.equals("GET") || method.equals("HEAD")) &&
@@ -104,12 +114,10 @@ public abstract class LocalHTTPServer {
else if (filename.endsWith(".jpg"))
type = "image/jpeg";
else type = "text/html";
try {
out.write("HTTP/1.1 200 OK\r\nContent-Type: ".getBytes());
out.write(type.getBytes());
out.write("\r\nCache-Control: max-age=86400\r\n\r\n".getBytes());
FileUtil.readFile(filename, themesDir.getAbsolutePath(), out);
} catch (IOException ioe) {}
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\nConnection: close\r\nProxy-Connection: close\r\n\r\n".getBytes("UTF-8"));
FileUtil.readFile(filename, themesDir.getAbsolutePath(), out);
return;
}
}
@@ -153,31 +161,24 @@ public abstract class LocalHTTPServer {
//System.err.println("book : \"" + book + "\"");
//System.err.println("nonce : \"" + nonce + "\"");
if (proxyNonce.equals(nonce) && url != null && host != null && dest != null) {
try {
NamingService ns = I2PAppContext.getGlobalContext().namingService();
Properties nsOptions = new Properties();
nsOptions.setProperty("list", book);
if (referer != null && referer.startsWith("http")) {
String from = "<a href=\"" + referer + "\">" + referer + "</a>";
nsOptions.setProperty("s", _("Added via address helper from {0}", from));
} else {
nsOptions.setProperty("s", _("Added via address helper"));
}
boolean success = ns.put(host, dest, nsOptions);
writeRedirectPage(out, success, host, book, url);
return;
} catch (IOException ioe) {}
NamingService ns = I2PAppContext.getGlobalContext().namingService();
Properties nsOptions = new Properties();
nsOptions.setProperty("list", book);
if (referer != null && referer.startsWith("http")) {
String from = "<a href=\"" + referer + "\">" + referer + "</a>";
nsOptions.setProperty("s", _("Added via address helper from {0}", from));
} else {
nsOptions.setProperty("s", _("Added via address helper"));
}
boolean success = ns.put(host, dest, nsOptions);
writeRedirectPage(out, success, host, book, url);
return;
}
try {
out.write(ERR_ADD);
out.flush();
} catch (IOException ioe) {}
return;
out.write(ERR_ADD.getBytes("UTF-8"));
} else {
out.write(ERR_404.getBytes("UTF-8"));
}
try {
out.write(ERR_404);
out.flush();
} catch (IOException ioe) {}
out.flush();
}
/** @since 0.8.7 */
@@ -193,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

@@ -0,0 +1,7 @@
<html>
<body>
<p>
A very simple HTTP server, used only for css and images on HTTP client proxy error pages.
</p>
</body>
</html>

View File

@@ -0,0 +1,14 @@
<html>
<body>
<p>
Implementation of preconfigured tunnels, both for clients and servers,
and a UI for adding more and editing the configuration.
Includes special-purpose tunnels for IRC, SOCKS, HTTP, and more.
</p><p>
The entry point is TunnelControllerGroup, which is started from clients.config.
Individual tunnel configuration is in i2ptunnel.config.
The primary API is TunnelControllerGroup and TunnelController.
Other classes may not be maintained as a stable API.
</p>
</body>
</html>

View File

@@ -55,9 +55,12 @@ public class I2PSOCKSIRCTunnel extends I2PSOCKSTunnel {
Thread in = new I2PAppThread(new IrcInboundFilter(clientSock, destSock, expectedPong, _log),
"SOCKS IRC Client " + id + " in", true);
in.start();
Thread out = new I2PAppThread(new IrcOutboundFilter(clientSock, destSock, expectedPong, _log),
"SOCKS IRC Client " + id + " out", true);
out.start();
//Thread out = new I2PAppThread(new IrcOutboundFilter(clientSock, destSock, expectedPong, _log),
// "SOCKS IRC Client " + id + " out", true);
Runnable out = new IrcOutboundFilter(clientSock, destSock, expectedPong, _log);
// we are called from an unlimited thread pool, so run inline
//out.start();
out.run();
} catch (SOCKSException e) {
if (_log.shouldLog(Log.WARN))
_log.warn("Error from SOCKS connection", e);

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");
}
@@ -56,7 +53,9 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase {
I2PSocket destSock = serv.getDestinationI2PSocket(this);
Thread t = new I2PTunnelRunner(clientSock, destSock, sockLock, null, null, mySockets,
(I2PTunnelRunner.FailCallback) null);
t.start();
// we are called from an unlimited thread pool, so run inline
//t.start();
t.run();
} catch (SOCKSException e) {
if (_log.shouldLog(Log.WARN))
_log.warn("Error from SOCKS connection", e);

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() {

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