Compare commits

..

118 Commits

Author SHA1 Message Date
zzz
aebf16add7 0.6.1.33 version and news 2008-04-25 13:57:38 +00:00
zzz
1de0563c94 update forum link on susidns page 2008-04-25 13:22:41 +00:00
dev
c6059b9d85 merge of '20e06eb5e2ee39991682cae68511fca1944cd5b0'
and '8adc3b02e35ce3275e813ca9c64d75d02a0d9310'
2008-04-20 19:21:35 +00:00
dev
f68c9242a9 added news-entry for trac 2008-04-20 19:21:13 +00:00
zzz
51838ba051 * Outbound message/Reachability:
- Fix a bug from -19 causing the persistent lease selection
        removed in -17 to be back again
      - Use netDb-listed-unreachable instead of detected-unreachable
        for exclusion of unreachable peers from selected leases,
        as there are potential anonymity problems with using
        detected-unreachable
      - Tweak logging some more
    * NetDb stats: Remove a couple more including the inefficient stat_identities
2008-04-20 18:02:15 +00:00
zzz
cf50b7eac1 * Reachability:
- Track unreachable peers persistently
        (i.e. separately from shitlist, and not cleared when they contact us)
      - Exclude detected unreachable peers from inbound tunnels
      - Exclude detected unreachable peers from selected leases
      - Exclude detected unreachable floodfill peers from lookups
      - Show unreachable status on profiles.jsp
2008-04-17 18:59:15 +00:00
zzz
2edd84e088 * SSU/Reachability:
- Extend shitlist time from 4-8m to 40-60m
      - Add some shitlist logging
      - Don't shitlist twice when unreachable on all transports
      - Exclude netDb-listed unreachable peers from inbound tunnels;
        this won't help much since there are very few of these now
      - Remove 10s delay on inbound UDP connections used for the
        0.6.1.10 transition
      - Track and display UDP connection direction on peers.jsp
      - Show shitlist status in-line on profiles.jsp
2008-04-16 20:51:57 +00:00
zzz
5ba1e458c6 * SSU Reachability/PeerTestManager:
- Back out strict peer ordering until we fix SSU
      - Back out persistent lease selection until we fix SSU
      - Fix detection of UDP REJECT_UNSOLICITED by recording status on expiration
      - Increase known Charlie time to 10m; 3m wasn't enough
      - Don't continue retransmitting peer test if we know Charlie
      - Don't run multiple peer tests at once
      - Tighten test frequency range to 6.5-19.5m, was 0-26m
2008-04-15 18:27:43 +00:00
zzz
0b600669c7 * Addressbook: Disallow '.-' and '-.' in host names
* NTCP: Don't drop a connection unless both directions are idle;
            Fix idle time for outbound connections
    * Outbound message: Make sure cached lease is in current leaseSet
    * Stats: Put all NetworkDatabase stats in same group
    * TunnelPool: Stop building tunnels and leaseSets after client shutdown
    * i2psnark: Add locking to prevent two I2CP connections
2008-04-12 21:34:25 +00:00
dev
215eb14d38 no need anymore to set I2P-Home when using eepget 2008-04-07 18:54:48 +00:00
zzz
20ff2f5bdc Minor cleanups, -15 2008-04-07 17:42:54 +00:00
zzz
edc02e5efa Implement outbound bandwidth limiting for i2psnark 2008-04-07 17:41:58 +00:00
zzz
d57356f807 Reduce priority of participating traffic 2008-04-07 17:41:19 +00:00
zzz
a7a6c75ac5 * ExploratoryPeerSelector: Try NonFailing even more
* HostsTxtNamingService: Add reverse lookup support
    * Outbound message: Minor cleanup
    * i2psnark TrackerCLient: Minor cleanup
    * checklist.txt: Minor edit
    * hosts.txt: Add perv.i2p, false.i2p, mtn.i2p2.i2p
    * i2ptunnel.config: Change CVS client to mtn
    * netdb.jsp: Show leaseSet destinations using reverse lookup
    * profiles.jsp: First cut at showing floodfill data
2008-03-30 21:50:35 +00:00
zzz
b9e2def552 * Send messages for the same destination to the same inbound
lease to reduce out-of-order delivery.
    * ExploratoryPeerSelector: Back out the floodfill peer exclusion
      for now, as it prevents speed rating of those peers
2008-03-27 13:03:16 +00:00
zzz
4d7417401c * ReseedHandler: Support multiple urls,
add netdb.i2p2.de as a 2nd default
2008-03-26 20:15:47 +00:00
zzz
40a9e959e8 * i2psnark:
- Add support for secondary open trackers
      - Refactor and simplify the TrackerClient code
      - Add welterde's tracker to the default list
      - Don't have eepget retry announces
      - Slow down tracker contacts if they've failed for a while
      - Add some debug support showing connections (?p=2)
2008-03-25 21:54:54 +00:00
zzz
42bbb4a9ff * NewsFetcher: Fix bug causing fetch every 10m 2008-03-22 17:10:49 +00:00
zzz
9500a55532 * Tunnel Testing:
- Fix counting so it really takes 4 consecutive failures
        rather than 4 total to remove a tunnel
      - Credit or blame goes to the exploratory tunnel as well
        as the tunnel being tested
      - Adjust tunnel test timeout based on tunnel length
    * ExploratoryPeerSelector: Tweak logging
    * ProfileOrganizer: Adjust integration calculation again
    * build.xml: Add to help
    * checklist.txt: Tweak
    * readme.html: Fix forum links
    * netDb: Remove tunnel.testFailedTime
2008-03-22 13:07:38 +00:00
zzz
0556f15068 remove corrupt sex0r.i2p from hosts.txt 2008-03-21 15:23:10 +00:00
zzz
6e981874a5 * ExploratoryPeerSelector:
- Exclude floodfill peers
      - Tweak the HighCap vs. NonFailing decision
    * i2psnark: Increase retries for .torrent fetch
    * IRC Proxy: Prevent mIRC from sending an alternate DCC request
      containing an IP
    * readme.html: Reorder some items
    * Stats: Add some more required stats
    * Streaming lib: Fix slow start to be exponential growth,
      fix congestion avoidance to be linear growth.
      Should speed up local connections a lot, and remote
      connections a little.
2008-03-19 00:20:15 +00:00
zzz
8886d61caa forum news 2008-03-16 16:12:57 +00:00
zzz
b6fe81a982 Floodfill Search: Prefer heard-from, unfailing, unshitlisted floodfill peers 2008-03-14 22:53:18 +00:00
zzz
e7cdb965ba * ProfileOrganizer:
- Use more recent stats to calculate integrationory.txt
       - Show that fast peers are also high-capacity on profiles.jsp
    * readme.html: Update Syndie link
    * TunnelPool: Update comments
    * netDb: Report 1-2h uptime as 90m to further frustrate tracking,
      get rid of the 60s tunnel stats
      (effective as of .33 to provide cover)
2008-03-13 23:13:32 +00:00
zzz
4fa4357bf1 * Floodfill Search:
- Fix a bug that caused a single FloodfillOnlySearchJob
         instance to be run multiple times, with unpredictable
         results
       - Select ff peers randomly to improve reliability
       - Add some bulletproofing
2008-03-13 20:23:46 +00:00
zzz
46307c60d4 * ProfileOrganizer:
- Don't require a peer to be high-capacity to be
         well-integrated (not used for anything right now,
         but want to get it right for possible floodfill verification)
       - Don't fall back to median for high-capacity threshold
         if the mean is higher than the median, this prevents
         frequent large high-capacity counts
       - Fix high-capacity selector that picked one too many
    * Console: put well-integrated count back in the summary
2008-03-11 22:59:47 +00:00
zzz
e6a0c2f4f0 * EepGet: Fix byte count for bytesTransferred status listeners
(fixes command line status)
    * UpdateHandler:
       - Fix byte count display
       - Display final status on router console
       - Don't allow multiple update jobs to queue up
       - Increase max retries
       - Code cleanup
       - Don't show 'check for update' button when update in progress
       - Enhance error messages
2008-03-10 16:27:40 +00:00
zzz
cb41bf6023 NetDb: Comment out published netDb stats disabled for .32 2008-03-10 16:22:24 +00:00
zzz
d23c8a8331 -2 2008-03-09 14:55:44 +00:00
zzz
b1beb46ca2 propagate from branch 'i2p.i2p.i2p-0.6.1.33-pre' (head adbe93ae091c4ca78306ef94968a0c1d788e2c01)
to branch 'i2p.i2p' (head f541ec6c1ca7ffae49e31ee75559695d64152fa1)
2008-03-09 14:45:31 +00:00
complication
6606c83cb2 2008-03-09 Complication
* Give the Jetty build file ability to ask permission
      before downloading the Jetty archive from the web,
      and to verify its SHA1 + MD5 hashes. Adjust the main build file
      in accordance with this change.
    * Improve the release checklist.
2008-03-08 20:37:45 +00:00
zzz
5998f5c9bd * ClientPeerSelector: Implement strict ordering of peers,
based on XOR distance from a random hash
      separately generated for each tunnel pool
2008-03-07 23:24:49 +00:00
zzz
cffcbe5f94 update news and version numbers to .32 2008-03-07 15:08:26 +00:00
zzz
0c75725f5e * ProfileOrganizer, TunnelPoolSettings, ClientPeerSelector:
- Prevent peers with matching IPs from joining same tunnel.
        Match 0-4 bytes of IP (0=off, 1=most restrictive, 4=least).
        Default is 2 (disallow routers in same /16).
        Set with router.defaultPool.IPRestriction=x
      - Comment out unused RebuildPeriod pool setting
      - Add random key to pool in preparation for XOR peer ordering
2008-03-07 14:36:40 +00:00
zzz
5ef325408c Optimize naming lookups for a destkey 2008-03-07 14:31:36 +00:00
zzz
d957712e88 Change a common wtf error to a warn 2008-03-06 14:03:49 +00:00
zzz
9233c2ed4c Add create account link in susimail 2008-03-06 14:00:33 +00:00
zzz
7ad54eb749 * Stats: Add code to disable most stats to save memory.
Set on configstats.jsp or set stat.full=false to disable the stats.
      (true by default for now)
2008-03-05 18:44:45 +00:00
zzz
5740e20c62 -3201 2008-03-05 14:25:39 +00:00
zzz
0a9114fc2f add a i2psnark StartAll button 2008-03-05 14:20:02 +00:00
zzz
71ddfa42e1 * i2psnark: Don't do a naming lookup for Base64 destkeys 2008-03-05 14:19:19 +00:00
zzz
1ecb84f3fb * Naming: Make HostsTxt the sole default NamingService
(was Meta = PetName + HostsTxt)
    * Naming: Add two new experimental NamingServices, EepGet and Exec,
      not enabled by default -
      see source comments in core/java/src/net/i2p/client/naming
      for configuration instructions
2008-03-05 14:16:04 +00:00
zzz
c46b06fb81 Fix netdb.knownLeaseSets count reported by floodfill routers 2008-03-01 16:13:41 +00:00
zzz
a7397879aa correct instructions 2008-02-29 16:50:37 +00:00
zzz
9b86da7ce5 upcoming .32 news 2008-02-29 14:51:24 +00:00
zzz
c68977ca8c * i2ptunnel: Add 3-hop option to edit.jsp to match configtunnels.jsp
* i2psnark: Remove orion and gaytorrents from default tracker list
    * Remove orion from jump list and from eepsite_index.html
    * Jbigi: Change jbigi version to 4.2.2 in build scripts - tested by amiga
    * Capitalize OutboundMessageDistributor job name
    * TunnelPool: Add a warning if all tunnels are backlogged
2008-02-27 15:18:32 +00:00
zzz
bc7bd628db * Reintroduce NTCP backlog pushback, with switch back to
previous tunnel when no longer backlogged
    * Catch an nio exception in an NTCP logging statement if loglevel is WARN
    * IRC Proxy: terminate all messages with \r\n (thanks TrivialPursuit!)
2008-02-26 19:33:11 +00:00
zzz
bc7ab39131 +x the c build files 2008-02-21 14:53:50 +00:00
zzz
100163e03b * Raise inbound default bandwidth to 32KBps
* Fix config.jsp that showed 0KBps share bandwidth by default
2008-02-21 14:05:33 +00:00
zzz
49c02f13b2 -5 2008-02-19 15:39:44 +00:00
zzz
40f072e25e Display capabilities on profiles.jsp 2008-02-19 15:32:39 +00:00
zzz
918b1acb8f * Tunnels: Enforce max tunnel length of 8, catch an index error
http://forum.i2p/viewtopic.php?t=2561
2008-02-19 15:28:41 +00:00
zzz
bc16078e3f Remove some stats from netDb, effective in .32 2008-02-19 15:22:46 +00:00
zzz
4a8dbd0634 * Addressbook: Disallow '--' in host names except in IDN,
add some reserved host names
2008-02-19 15:21:58 +00:00
zzz
38c0184f95 clarify the i2ptunnel edit page dropdowns 2008-02-19 15:20:42 +00:00
zzz
68829ddb99 merge of 'cc7dee6f711dd10db6c1f42af8dc7ba6f6b0002d'
and 'dc2fa2d01da4c7b3733d4dadb85d757d592c1fa6'
2008-02-19 15:16:53 +00:00
zzz
19089bd6a7 * Fix race in TunnelDispatcher which caused
participating tunnel count to seesaw -
      should increase network capacity
    * Leave participating tunnels in 10s batches for efficiency
    * Update participating tunnel ratestat when leaving a tunnel too,
      to generate a smoother graph
    * Fix tunnel.participatingMessageCount stat to include all
      participating tunnels, not just outbound endpoints
    * Simplify Expire Tunnel job name
2008-02-16 16:25:21 +00:00
zzz
69cc0afd1b * PersistentDataStore: Write out 300 records every 10 min
rather than 1 every 10 sec;
      Don't store leasesets to disk or read them in
    * Combine rates for pools with the same length setting
      in the new tunnel build algorithm
    * Clarify a log message in the UpdateHandler
2008-02-13 21:42:09 +00:00
zzz
d2f3a262db * Make graphs clickable to get larger graphs
* Change SimpleTimer CRIT to a WARN, increase threshold
    * Checklist update
2008-02-13 11:49:24 +00:00
dev
c1703b872d probably fixed a bug in udp-transport 2008-02-11 20:45:33 +00:00
dev
f7b0e8181b merge of '1d753ff05fc1c942cf6ce8feeadfaa577bff27ab'
and 'e20c0075f57440edcebaac0009a0ef0327d563cc'
2008-02-11 20:38:47 +00:00
zzz
43f2695901 * Add new tunnel build algorithm (preliminary)
* Change NTCP backlogged message from error to warning
    * Checklist updates
2008-02-10 18:29:21 +00:00
complication
ea0d4ffd7f * 2008-02-10 0.6.1.31 released
2008-02-10 Complication
    * Update news and version numbers
2008-02-10 13:59:20 +00:00
dev
0ed29573a7 minor 2008-02-09 13:18:22 +00:00
zzz
1365d3e3b9 Remove orion reference in dnfh error page 2008-02-08 21:04:23 +00:00
zzz
40befb5a92 remove comments from hosts.txt 2008-02-08 19:16:48 +00:00
zzz
9c16eec361 checklist updates, +x some files 2008-02-08 00:15:32 +00:00
zzz
093c69637d * build.xml: Add some apps to javadoc
* checklist.txt: Add some things
    * news.xml: Minor edit
    * runplain.sh: Add some comments
2008-02-06 16:38:23 +00:00
zzz
134ec7acea * news.xml: make links relative
* wrapper.config: Add some comments
* checklist.txt: Add some things
2008-02-05 03:14:18 +00:00
complication
0802a5ae40 2008-02-05 Complication
* Change the dates too (sorry for such forgetfulness!)
2008-02-04 23:52:11 +00:00
complication
14ddfb360f 2008-02-04 Complication
* Also use the new key for checking, and add it into news.xml
2008-02-04 23:20:28 +00:00
complication
78ad831028 2008-02-04 Complication
* Added my release signing key into TrustedUpdate.java
2008-02-04 21:34:52 +00:00
zzz
22f1684262 * NewsFetcher: Change fetch failed from error to warning
* installer: Fix URL and "email"
    * checklist.txt: New release checklist
2008-01-31 19:56:00 +00:00
zzz
83f51b4a66 2008-01-29 zzz
* Addressbook: Change default subscription
    * ConfigUpdateHandler: Change default news URL
    * initialNews.xml: Update version to .31
    * news.xml: More updates
    * hosts.txt: Add i2p-projekt.i2p
    * readme.html: More URL updates
    * SusiDNS: Change references to default subscription
2008-01-29 22:20:04 +00:00
zzz
9c28de0704 2008-01-28 zzz
* news.xml: Updates, still preliminary
    * ReseedHandler: Change default URL
    * i2ptunnel.config: Change default outproxies
    * readme.html: Change *.i2p.net URLs
    * help.jsp: Change *.i2p.net URLs
    * eepsite_index.html: Change stats.i2p addressbook subscription URL
    * hosts.txt: Add krabs.i2p, true.i2p, www.i2p2.i2p
2008-01-28 19:24:12 +00:00
zzz
c69fda2298 Drop unused directories 2008-01-27 14:48:50 +00:00
zzz
cabb22331b Drop unused directories 2008-01-27 14:42:04 +00:00
zzz
5b3aca29a8 replace orion.i2p with perv.i2p/stats.cgi 2008-01-09 22:40:33 +00:00
zzz
f35cbf59d8 * NewsFetcher: add last-modified support, reduce number of retries
* Error pages: add icon and logo,
        clarify 'destination not found' and 'proxy not found' pages
2008-01-09 04:11:12 +00:00
zzz
a96119d09b 2008-01-08 zzz
* addressbook: Limit size of subscribed hosts.txt,
        don't save old etag or last-modified data
    * EepGet: Add some logging,
        enforce size limits even when size not in returned header,
        don't return old etag or last-modified data,
        don't call transferFailed listener more than once
2008-01-09 02:15:43 +00:00
zzz
2711294aee (zzz) sign my update signing key 2008-01-09 01:56:38 +00:00
zzz
f838b1828b 2008-01-07 zzz
* profiles.jsp formatting cleanup
    * NTCP: Reduce max idle time from 60m to 20m
    * NTCP: Fix idle time on connections with zero messages,
      correctly drop these connections
2008-01-07 08:09:43 +00:00
zzz
fbf6282c1a 2008-01-03 zzz
* addressbook: Do basic validation of hostnames and destkeys
    * susidns: Add support for the private addressbook,
      update the text and links somewhat
2008-01-04 02:37:24 +00:00
zzz
5195a5c1fc 2008-01-02 zzz
* Add stats.i2p to the jump list
    * Impose 20MB limit on POSTs and catch OOMs in POST
    * eepsite_index.html: add stats.i2p services
    * addressbook: log source of new keys; disallow dests > 516 bytes
    * addressbook: convert hostnames to lower case to prevent duplicates
    * susidns: generalize references to orion
2008-01-02 22:08:48 +00:00
zzz
62b18b18b5 2007-12-29 zzz
* Tweak IRC inbound PONG filtering to fix xchat/BitchX lagometers
2007-12-30 03:45:09 +00:00
zzz
7c8f519b35 2007-12-29 zzz
* Allow commas in router.trustedUpdateKeys and router.updateURL again
2007-12-29 23:59:24 +00:00
zzz
d6fb979616 2007-12-29 zzz
* Change default news host from dev.i2p.net to dev.i2p
2007-12-29 22:15:11 +00:00
zzz
f568d21969 2007-12-29 zzz
* Change jetty timeout from 30 to 60 sec (thanks sponge!)
2007-12-29 21:08:29 +00:00
zzz
7fe9d590f5 2007-12-28 zzz
* Add zzz's update signing key
2007-12-28 20:27:16 +00:00
complication
0a1240ebfd 2007-12-26 Complication
* Improve reseed handler (less repetitive code,
      avoid reporting errors when less than 10% of fetches fail)
2007-12-26 20:55:07 +00:00
complication
4e68f2a157 2007-12-26 Complication
* Escape both CR, LF and CR LF line breaks in Router.saveConfig()
      and unescape them in DataHelper.loadProps() to support
      saving and loading config properties with line breaks
    * Change the update URLs textbox into a textarea like keys have,
      so different URLs go on different lines
    * Modify TrustedUpdate to provide a method which supplies a key list
      delimited with CR LF line breaks
    * Modify DEFAULT_UPDATE_URL to supply a default URL list
      delimited with CR LF line breaks
    * Modify selectUpdateURL() to handle URL lists
      delimited by any kind of line breaks
    * Start saving trusted update keys
    * Improve formatting on configupdate.jsp
2007-12-26 08:14:54 +00:00
zzz
e9bd6907d1 2007-12-22 zzz
* Add support for multiple update URLs
    * Change default for update to use i2p proxy,
      add several URLs as defaults
    * Enable trusted key form on configupdate.jsp
2007-12-22 23:58:46 +00:00
zzz
b20495c39f (zzz) Clarify the 'destination not found' error page 2007-12-22 20:54:44 +00:00
zzz
0ecbc4c27b (zzz) remove anonymitytracker from default tracker list, not seen in over 6 months 2007-12-17 02:33:05 +00:00
zzz
4d5b1d4c3f 2007-12-10 zzz
* Fix NPE in CLI TrustedUpdate keygen
2007-12-10 22:22:59 +00:00
complication
17b719f3f7 2007-12-02 Complication
* Commit SAM v2 patch from mkvore (thank you!)
    * Minor reformatting to preserve consistent whitespace
      in old SAM classes (new classes unaltered)
2007-12-03 04:19:25 +00:00
complication
979a3e98d8 2007-12-01 Complication
* Separate the checks "does Jetty .zip file need downloading"
      and "does Jetty .zip file need extracting" in the Jetty buildfile.
      First download (unless already done), then extract (unless done).
2007-12-02 03:13:15 +00:00
zzz
c6a1112f0a 2007-11-26 zzz
* i2psnark: add timeout for receive inactivity
2007-11-26 21:53:58 +00:00
zzz
4ebcc95d9f 2007-11-24 zzz
* i2psnark: increase streaming lib write timeout to 240 sec and change
      timeout action from "ping" to "disconect", as the fix in .30 to
      honor options on outbound connections led to hung outbound connections
      (bitfield never transmitted, connection never dropped)
2007-11-24 20:22:45 +00:00
zzz
7e59ce27fa (zzz) i2phost.i2p => i2host.i2p 2007-11-06 20:15:25 +00:00
zzz
22345a264e (zzz) fix new jump server typo 2007-11-06 19:53:06 +00:00
jrandom
03739996da 2007-11-06 jrandom
* add i2phost.i2p to the jump list
2007-11-06 11:26:01 +00:00
zzz
819a72d4f6 2007-10-11 zzz
* IRC Proxy: Fix several possible anonymity holes:
      - Block CTCP in NOTICE messages
      - Block CTCP anywhere in PRIVMSG and NOTICE, not just at first character
      - Check for lower case commands
    (Thanks sponge!)
2007-10-11 06:03:21 +00:00
jrandom
e480931e20 2007-10-07 jrandom
* back out the NTCP backlog pushback, as it could be used to mount an
      active anonymity attack.
2007-10-08 04:11:36 +00:00
zzz
3f01d0a69e (zzz) .30 details 2007-10-08 04:03:40 +00:00
jrandom
f67f47f0cd 0.6.1.30 2007-10-08 03:09:35 +00:00
jrandom
5ad6ee60eb 0.6.1.30 2007-10-08 03:01:47 +00:00
complication
5accba6cdc 2007-10-07 Complication
* Fix an issue in EepGet whereby sending of "etag" and "lastModified" headers
      broke retrying.
2007-10-08 02:36:17 +00:00
zzz
313e1704df 2007-09-27 zzz
* Implement pushback of NTCP transport backlog to the outbound tunnel selection code
    * Clean up the NTCP and UDP tables on peers.jsp to be consistent,
      fix some of the sorting
2007-09-27 03:52:32 +00:00
zzz
cf4d2b17c9 2007-09-22 zzz
* Send messages for the same destination out the same outbound
      tunnel to reduce out-of-order delivery.
2007-09-23 02:44:34 +00:00
zzz
9145eedc35 2007-09-19 zzz
* i2psnark: Fix broken multifile torrent Delete;
        cleanup Storage resources in AddTorrent;
        don't autostart torrent after Create
2007-09-20 01:44:02 +00:00
zzz
b772179077 2007-09-18 zzz
* eepsite_index.html: Add links to trevorreznik address book
    * streaming lib: Fix SocketManagerFactory to honor options on outbound connections
    * streaming lib: Fix setDefaultOptions() when called with a ConnectionOptions parameter
    * i2psnark: Don't make outbound connections to already-connected peers
    * i2psnark: Debug logging cleanup
2007-09-18 19:09:19 +00:00
zzz
9054a196ce 2007-09-14 zzz
* eepget: Increase header timeout to 45s
    * HTTP proxy: Return a better error message for localhost requests
    * tunnels: Fix PooledTunnelCreatorConfig memory leak
2007-09-15 01:58:30 +00:00
zzz
d28a96ac7d 2007-09-09 zzz
* eepget: Add support for Last-Modified and If-Modified-Since
    * addressbook: Finish incomplete support for Last-Modified
2007-09-09 17:38:53 +00:00
zzz
9c73f80ac3 (zzz) Copy over SocketTimeout.java file from syndie for EepGet.java 2007-09-08 20:21:15 +00:00
jrandom
20c46cff04 synced up with the eepget from the syndie source tree (allowing better
control of timeouts and transparent redirection).  the users of eepget
in this source tree don't necessarily use the timeout controls, though
they can be updated to do so
2007-09-08 02:24:01 +00:00
jrandom
f332513755 added trevorreznik.i2p 2007-09-02 01:36:54 +00:00
zzz
cb69a66498 (zzz) .29 announcement 2007-08-24 02:34:40 +00:00
141 changed files with 4776 additions and 1166 deletions

View File

@@ -17,6 +17,10 @@
# Contains the addresses from your master address book
# and your subscribed address books. (../userhosts.txt)
#
# private_addressbook The path to the private address book used by the router.
# This is used only by the router and SusiDNS.
# It is not published by addressbook. (../privatehosts.txt)
#
# published_addressbook The path to the copy of your address book made
# available on i2p. (../eepsite/docroot/hosts.txt)
#
@@ -35,6 +39,7 @@ proxy_host=localhost
proxy_port=4444
master_addressbook=myhosts.txt
router_addressbook=../userhosts.txt
private_addressbook=../privatehosts.txt
published_addressbook=../eepsite/docroot/hosts.txt
log=log.txt
subscriptions=subscriptions.txt

View File

@@ -66,6 +66,7 @@ public class AddressBook {
* where key is a human readable name, and value is a base64 i2p
* destination.
*/
/* unused
public AddressBook(String url, String proxyHost, int proxyPort) {
this.location = url;
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), true,
@@ -79,22 +80,26 @@ public class AddressBook {
}
new File("addressbook.tmp").delete();
}
*/
/**
* Construct an AddressBook from the Subscription subscription. If the
* address book at subscription has not changed since the last time it was
* read or cannot be read, return an empty AddressBook.
* Set a maximum size of the remote book to make it a little harder for a malicious book-sender.
*
* @param subscription
* A Subscription instance pointing at a remote address book.
*/
static final long MAX_SUB_SIZE = 3 * 1024 * 1024l; //about 5,000 hosts
public AddressBook(Subscription subscription, String proxyHost, int proxyPort) {
this.location = subscription.getLocation();
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), true,
proxyHost, proxyPort, 0, "addressbook.tmp",
subscription.getLocation(), true, subscription.getEtag());
get.fetch();
subscription.setEtag(get.getETag());
proxyHost, proxyPort, 0, -1l, MAX_SUB_SIZE, "addressbook.tmp", null,
subscription.getLocation(), true, subscription.getEtag(), subscription.getLastModified(), null);
if (get.fetch()) {
subscription.setEtag(get.getETag());
subscription.setLastModified(get.getLastModified());
}
try {
this.addresses = ConfigParser.parse(new File("addressbook.tmp"));
} catch (IOException exp) {
@@ -151,6 +156,37 @@ public class AddressBook {
return this.addresses.toString();
}
/**
* Do basic validation of the hostname and dest
* hostname was already converted to lower case by ConfigParser.parse()
*/
private static boolean valid(String host, String dest) {
return
host.endsWith(".i2p") &&
host.length() > 4 &&
host.length() <= 67 && // 63 + ".i2p"
(! host.startsWith(".")) &&
(! host.startsWith("-")) &&
host.indexOf(".-") < 0 &&
host.indexOf("-.") < 0 &&
host.indexOf("..") < 0 &&
// IDN - basic check, not complete validation
(host.indexOf("--") < 0 || host.startsWith("xn--") || host.indexOf(".xn--") > 0) &&
host.replaceAll("[a-z0-9.-]", "").length() == 0 &&
// some reserved names that may be used for local configuration someday
(! host.equals("proxy.i2p")) &&
(! host.equals("router.i2p")) &&
(! host.equals("console.i2p")) &&
(! host.endsWith(".proxy.i2p")) &&
(! host.endsWith(".router.i2p")) &&
(! host.endsWith(".console.i2p")) &&
dest.length() == 516 &&
dest.endsWith("AAAA") &&
dest.replaceAll("[a-zA-Z0-9~-]", "").length() == 0
;
}
/**
* Merge this AddressBook with AddressBook other, writing messages about new
* addresses or conflicts to log. Addresses in AddressBook other that are
@@ -169,7 +205,7 @@ public class AddressBook {
String otherKey = (String) otherIter.next();
String otherValue = (String) other.addresses.get(otherKey);
if (otherKey.endsWith(".i2p") && otherValue.length() >= 516) {
if (valid(otherKey, otherValue)) {
if (this.addresses.containsKey(otherKey) && !overwrite) {
if (!this.addresses.get(otherKey).equals(otherValue)
&& log != null) {
@@ -184,7 +220,7 @@ public class AddressBook {
this.modified = true;
if (log != null) {
log.append("New address " + otherKey
+ " added to address book.");
+ " added to address book. From: " + other.location);
}
}
}

View File

@@ -60,6 +60,7 @@ public class ConfigParser {
* a single key, value pair on each line, in the format: key=value. Lines
* starting with '#' or ';' are considered comments, and ignored. Lines that
* are obviously not in the format key=value are also ignored.
* The key is converted to lower case.
*
* @param input
* A BufferedReader with lines in key=value format to parse into
@@ -77,7 +78,7 @@ public class ConfigParser {
inputLine = ConfigParser.stripComments(inputLine);
String[] splitLine = inputLine.split("=");
if (splitLine.length == 2) {
result.put(splitLine[0].trim(), splitLine[1].trim());
result.put(splitLine[0].trim().toLowerCase(), splitLine[1].trim());
}
inputLine = input.readLine();
}
@@ -301,4 +302,4 @@ public class ConfigParser {
new FileWriter(file, false)));
}
}
}

View File

@@ -98,7 +98,8 @@ public class Daemon {
AddressBook router = new AddressBook(routerFile);
List defaultSubs = new LinkedList();
defaultSubs.add("http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/hosts.txt");
// defaultSubs.add("http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/hosts.txt");
defaultSubs.add("http://www.i2p2.i2p/hosts.txt");
SubscriptionList subscriptions = new SubscriptionList(subscriptionFile,
etagsFile, lastModifiedFile, defaultSubs, (String) settings

View File

@@ -14,7 +14,7 @@
srcdir="./src"
debug="true" deprecation="on" source="1.3" target="1.3"
destdir="./build/obj"
classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../ministreaming/java/build/mstreaming.jar" />
classpath="../../../core/java/build/i2p.jar:../../../router/java/build/router.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../ministreaming/java/build/mstreaming.jar" />
</target>
<target name="jar" depends="builddep, compile">
<jar destfile="./build/i2psnark.jar" basedir="./build/obj" includes="**/*.class" excludes="**/*Servlet.class">

View File

@@ -34,6 +34,7 @@ public class I2PSnarkUtil {
private boolean _configured;
private Set _shitlist;
private int _maxUploaders;
private int _maxUpBW;
private I2PSnarkUtil() {
_context = I2PAppContext.getGlobalContext();
@@ -79,6 +80,11 @@ public class I2PSnarkUtil {
_configured = true;
}
public void setMaxUpBW(int limit) {
_maxUpBW = limit;
_configured = true;
}
public String getI2CPHost() { return _i2cpHost; }
public int getI2CPPort() { return _i2cpPort; }
public Map getI2CPOptions() { return _opts; }
@@ -86,11 +92,12 @@ public class I2PSnarkUtil {
public int getEepProxyPort() { return _proxyPort; }
public boolean getEepProxySet() { return _shouldProxy; }
public int getMaxUploaders() { return _maxUploaders; }
public int getMaxUpBW() { return _maxUpBW; }
/**
* Connect to the router, if we aren't already
*/
public boolean connect() {
synchronized public boolean connect() {
if (_manager == null) {
Properties opts = new Properties();
if (_opts != null) {
@@ -104,9 +111,9 @@ public class I2PSnarkUtil {
if (opts.getProperty("outbound.nickname") == null)
opts.setProperty("outbound.nickname", "I2PSnark");
if (opts.getProperty("i2p.streaming.inactivityTimeout") == null)
opts.setProperty("i2p.streaming.inactivityTimeout", "90000");
opts.setProperty("i2p.streaming.inactivityTimeout", "240000");
if (opts.getProperty("i2p.streaming.inactivityAction") == null)
opts.setProperty("i2p.streaming.inactivityAction", "2"); // 1 == disconnect, 2 == ping
opts.setProperty("i2p.streaming.inactivityAction", "1"); // 1 == disconnect, 2 == ping
if (opts.getProperty("i2p.streaming.initialWindowSize") == null)
opts.setProperty("i2p.streaming.initialWindowSize", "1");
if (opts.getProperty("i2p.streaming.slowStartGrowthRateFactor") == null)
@@ -160,8 +167,10 @@ public class I2PSnarkUtil {
/**
* fetch the given URL, returning the file it is stored in, or null on error
*/
public File get(String url) { return get(url, true); }
public File get(String url, boolean rewrite) {
public File get(String url) { return get(url, true, 0); }
public File get(String url, boolean rewrite) { return get(url, rewrite, 0); }
public File get(String url, int retries) { return get(url, true, retries); }
public File get(String url, boolean rewrite, int retries) {
_log.debug("Fetching [" + url + "] proxy=" + _proxyHost + ":" + _proxyPort + ": " + _shouldProxy);
File out = null;
try {
@@ -175,7 +184,7 @@ public class I2PSnarkUtil {
if (rewrite)
fetchURL = rewriteAnnounce(url);
//_log.debug("Rewritten url [" + fetchURL + "]");
EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, 1, out.getAbsolutePath(), fetchURL);
EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, retries, out.getAbsolutePath(), fetchURL);
if (get.fetch()) {
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
return out;
@@ -195,6 +204,8 @@ public class I2PSnarkUtil {
}
String getOurIPString() {
if (_manager == null)
return "unknown";
I2PSession sess = _manager.getSession();
if (sess != null) {
Destination dest = sess.getMyDestination();
@@ -206,15 +217,15 @@ public class I2PSnarkUtil {
Destination getDestination(String ip) {
if (ip == null) return null;
if (ip.endsWith(".i2p")) {
Destination dest = _context.namingService().lookup(ip);
if (dest != null) {
return dest;
} else {
try {
return new Destination(ip.substring(0, ip.length()-4)); // sans .i2p
} catch (DataFormatException dfe) {
return null;
}
if (ip.length() < 520) { // key + ".i2p"
Destination dest = _context.namingService().lookup(ip);
if (dest != null)
return dest;
}
try {
return new Destination(ip.substring(0, ip.length()-4)); // sans .i2p
} catch (DataFormatException dfe) {
return null;
}
} else {
try {
@@ -225,12 +236,22 @@ public class I2PSnarkUtil {
}
}
public String lookup(String name) {
Destination dest = getDestination(name);
if (dest == null)
return null;
return dest.toBase64();
}
/**
* Given http://blah.i2p/foo/announce turn it into http://i2p/blah/foo/announce
* Given http://KEY.i2p/foo/announce turn it into http://i2p/KEY/foo/announce
* Given http://tracker.blah.i2p/foo/announce leave it alone
*/
String rewriteAnnounce(String origAnnounce) {
int destStart = "http://".length();
int destEnd = origAnnounce.indexOf(".i2p");
if (destEnd < destStart + 516)
return origAnnounce;
int pathStart = origAnnounce.indexOf('/', destEnd);
String rv = "http://i2p/" + origAnnounce.substring(destStart, destEnd) + origAnnounce.substring(pathStart);
//_log.debug("Rewriting [" + origAnnounce + "] as [" + rv + "]");

View File

@@ -114,6 +114,14 @@ public class Peer implements Comparable
return "[unknown id] " + _id;
}
/**
* Returns socket (for debug printing)
*/
public String getSocket()
{
return sock.toString();
}
/**
* The hash code of a Peer is the hash code of the peerID.
*/
@@ -461,10 +469,12 @@ public class Peer implements Comparable
public long getInactiveTime() {
PeerState s = state;
if (s != null) {
PeerConnectionIn in = s.in;
PeerConnectionOut out = s.out;
if (out != null)
return System.currentTimeMillis() - out.lastSent;
else
if (in != null && out != null) {
long now = System.currentTimeMillis();
return Math.max(now - out.lastSent, now - in.lastRcvd);
} else
return -1; //"state, no out";
} else {
return -1; //"no state";

View File

@@ -68,6 +68,7 @@ class PeerCheckerTask extends TimerTask
// we will add them back to the end of the list.
List removed = new ArrayList();
int uploadLimit = coordinator.allowedUploaders();
boolean overBWLimit = coordinator.overUpBWLimit();
while (it.hasNext())
{
Peer peer = (Peer)it.next();
@@ -95,32 +96,29 @@ class PeerCheckerTask extends TimerTask
peer.setRateHistory(upload, download);
peer.resetCounters();
if (Snark.debug >= Snark.DEBUG)
{
Snark.debug(peer + ":", Snark.DEBUG);
Snark.debug(" ul: " + upload/KILOPERSECOND
+ " dl: " + download/KILOPERSECOND
+ " i: " + peer.isInterested()
+ " I: " + peer.isInteresting()
+ " c: " + peer.isChoking()
+ " C: " + peer.isChoked(),
Snark.DEBUG);
}
Snark.debug(peer + ":", Snark.DEBUG);
Snark.debug(" ul: " + upload/KILOPERSECOND
+ " dl: " + download/KILOPERSECOND
+ " i: " + peer.isInterested()
+ " I: " + peer.isInteresting()
+ " c: " + peer.isChoking()
+ " C: " + peer.isChoked(),
Snark.DEBUG);
// If we are at our max uploaders and we have lots of other
// interested peers try to make some room.
// (Note use of coordinator.uploaders)
if (((coordinator.uploaders == uploadLimit
&& coordinator.interestedAndChoking > 0)
|| coordinator.uploaders > uploadLimit)
|| coordinator.uploaders > uploadLimit
|| overBWLimit)
&& !peer.isChoking())
{
// Check if it still wants pieces from us.
if (!peer.isInterested())
{
if (Snark.debug >= Snark.INFO)
Snark.debug("Choke uninterested peer: " + peer,
Snark.INFO);
Snark.debug("Choke uninterested peer: " + peer,
Snark.INFO);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
@@ -129,11 +127,19 @@ class PeerCheckerTask extends TimerTask
it.remove();
removed.add(peer);
}
else if (overBWLimit)
{
Snark.debug("BW limit, choke peer: " + peer,
Snark.INFO);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
removedCount++;
}
else if (peer.isInteresting() && peer.isChoked())
{
// If they are choking us make someone else a downloader
if (Snark.debug >= Snark.DEBUG)
Snark.debug("Choke choking peer: " + peer, Snark.DEBUG);
Snark.debug("Choke choking peer: " + peer, Snark.DEBUG);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
@@ -146,8 +152,7 @@ class PeerCheckerTask extends TimerTask
else if (!peer.isInteresting() && !coordinator.completed())
{
// If they aren't interesting make someone else a downloader
if (Snark.debug >= Snark.DEBUG)
Snark.debug("Choke uninteresting peer: " + peer, Snark.DEBUG);
Snark.debug("Choke uninteresting peer: " + peer, Snark.DEBUG);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
@@ -162,9 +167,8 @@ class PeerCheckerTask extends TimerTask
&& download == 0)
{
// We are downloading but didn't receive anything...
if (Snark.debug >= Snark.DEBUG)
Snark.debug("Choke downloader that doesn't deliver:"
+ peer, Snark.DEBUG);
Snark.debug("Choke downloader that doesn't deliver:"
+ peer, Snark.DEBUG);
peer.setChoking(true);
uploaders--;
coordinator.uploaders--;
@@ -202,9 +206,8 @@ class PeerCheckerTask extends TimerTask
|| uploaders > uploadLimit)
&& worstDownloader != null)
{
if (Snark.debug >= Snark.DEBUG)
Snark.debug("Choke worst downloader: " + worstDownloader,
Snark.DEBUG);
Snark.debug("Choke worst downloader: " + worstDownloader,
Snark.DEBUG);
worstDownloader.setChoking(true);
coordinator.uploaders--;
@@ -217,7 +220,8 @@ class PeerCheckerTask extends TimerTask
}
// Optimistically unchoke a peer
coordinator.unchokePeer();
if (!overBWLimit)
coordinator.unchokePeer();
// Put peers back at the end of the list that we removed earlier.
coordinator.peers.addAll(removed);

View File

@@ -35,10 +35,13 @@ class PeerConnectionIn implements Runnable
private Thread thread;
private volatile boolean quit;
long lastRcvd;
public PeerConnectionIn(Peer peer, DataInputStream din)
{
this.peer = peer;
this.din = din;
lastRcvd = System.currentTimeMillis();
quit = false;
}
@@ -76,6 +79,7 @@ class PeerConnectionIn implements Runnable
// Wait till we hear something...
// The length of a complete message in bytes.
int i = din.readInt();
lastRcvd = System.currentTimeMillis();
if (i < 0)
throw new IOException("Unexpected length prefix: " + i);

View File

@@ -52,8 +52,8 @@ public class PeerCoordinator implements PeerListener
private long uploaded;
private long downloaded;
final static int RATE_DEPTH = 6; // make following arrays RATE_DEPTH long
private long uploaded_old[] = {0,0,0,0,0,0};
private long downloaded_old[] = {0,0,0,0,0,0};
private long uploaded_old[] = {-1,-1,-1,-1,-1,-1};
private long downloaded_old[] = {-1,-1,-1,-1,-1,-1};
// synchronize on this when changing peers or downloaders
final List peers = new ArrayList();
@@ -195,11 +195,17 @@ public class PeerCoordinator implements PeerListener
private long getRate(long array[])
{
long rate = 0;
int i = 0;
synchronized(array) {
for (int i = 0; i < RATE_DEPTH; i++)
for ( ; i < RATE_DEPTH; i++) {
if (array[i] < 0)
break;
rate += array[i];
}
}
return rate / (RATE_DEPTH * CHECK_PERIOD / 1000);
if (i == 0)
return 0;
return rate / (i * CHECK_PERIOD / 1000);
}
public MetaInfo getMetaInfo()
@@ -253,8 +259,8 @@ public class PeerCoordinator implements PeerListener
synchronized(peers)
{
Peer old = peerIDInList(peer.getPeerID(), peers);
if ( (old != null) && (old.getInactiveTime() > 4*60*1000) ) {
// idle for 4 minutes, kill the old con (64KB/4min = 273B/sec minimum for one block)
if ( (old != null) && (old.getInactiveTime() > 8*60*1000) ) {
// idle for 8 minutes, kill the old con (32KB/8min = 68B/sec minimum for one block)
if (_log.shouldLog(Log.WARN))
_log.warn("Remomving old peer: " + peer + ": " + old + ", inactive for " + old.getInactiveTime());
peers.remove(old);
@@ -313,6 +319,9 @@ public class PeerCoordinator implements PeerListener
synchronized(peers)
{
need_more = !peer.isConnected() && peers.size() < MAX_CONNECTIONS;
// Check if we already have this peer before we build the connection
Peer old = peerIDInList(peer.getPeerID(), peers);
need_more = need_more && ((old == null) || (old.getInactiveTime() > 8*60*1000));
}
if (need_more)
@@ -808,13 +817,18 @@ public class PeerCoordinator implements PeerListener
public int allowedUploaders()
{
if (Snark.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;
else
return MAX_UPLOADERS;
}
public boolean overUpBWLimit()
{
return Snark.overUpBWLimit();
}
}

View File

@@ -63,7 +63,7 @@ public class Snark
/**
* What level of debug info to show.
*/
public static int debug = NOTICE;
//public static int debug = NOTICE;
// Whether or not to ask the user for commands while sharing
private static boolean command_interpreter = true;
@@ -312,7 +312,7 @@ public class Snark
else
{
activity = "Getting torrent";
File torrentFile = I2PSnarkUtil.instance().get(torrent);
File torrentFile = I2PSnarkUtil.instance().get(torrent, 3);
if (torrentFile == null) {
fatal("Unable to fetch " + torrent);
if (false) return; // never reached - fatal(..) throws
@@ -505,6 +505,7 @@ public class Snark
int i = 0;
while (i < args.length)
{
/*
if (args[i].equals("--debug"))
{
debug = INFO;
@@ -525,7 +526,7 @@ public class Snark
catch (NumberFormatException nfe) { }
}
}
else if (args[i].equals("--port"))
else */ if (args[i].equals("--port"))
{
if (args.length - 1 < i + 1)
usage("--port needs port number to listen on");
@@ -772,7 +773,21 @@ public class Snark
totalUploaders += c.uploaders;
}
int limit = I2PSnarkUtil.instance().getMaxUploaders();
Snark.debug("Total uploaders: " + totalUploaders + " Limit: " + limit, Snark.DEBUG);
// Snark.debug("Total uploaders: " + totalUploaders + " Limit: " + limit, Snark.DEBUG);
return totalUploaders > limit;
}
public static boolean overUpBWLimit() {
PeerCoordinatorSet coordinators = PeerCoordinatorSet.instance();
if (coordinators == null)
return false;
long total = 0;
for (Iterator iter = coordinators.iterator(); iter.hasNext(); ) {
PeerCoordinator c = (PeerCoordinator)iter.next();
if (!c.halted())
total += c.getUploadRate();
}
long limit = 1024l * I2PSnarkUtil.instance().getMaxUpBW();
return total > limit;
}
}

View File

@@ -5,6 +5,7 @@ import java.util.*;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.router.RouterContext;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
@@ -30,13 +31,21 @@ public class SnarkManager implements Snark.CompleteListener {
public static final String PROP_EEP_HOST = "i2psnark.eepHost";
public static final String PROP_EEP_PORT = "i2psnark.eepPort";
public static final String PROP_UPLOADERS_TOTAL = "i2psnark.uploaders.total";
public static final String PROP_UPBW_MAX = "i2psnark.upbw.max";
public static final String PROP_DIR = "i2psnark.dir";
public static final String PROP_META_PREFIX = "i2psnark.zmeta.";
public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield";
public static final String PROP_AUTO_START = "i2snark.autoStart";
public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops
public static final String DEFAULT_AUTO_START = "false";
public static final String PROP_USE_OPENTRACKERS = "i2psnark.useOpentrackers";
public static final String DEFAULT_USE_OPENTRACKERS = "true";
public static final String PROP_OPENTRACKERS = "i2psnark.opentrackers";
public static final String DEFAULT_OPENTRACKERS = "http://tracker.welterde.i2p/a";
public static final int MIN_UP_BW = 2;
public static final int DEFAULT_MAX_UP_BW = 10;
private SnarkManager() {
_snarks = new HashMap();
_addSnarkLock = new Object();
@@ -72,6 +81,9 @@ public class SnarkManager implements Snark.CompleteListener {
public boolean shouldAutoStart() {
return Boolean.valueOf(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START+"")).booleanValue();
}
public boolean shouldUseOpenTrackers() {
return Boolean.valueOf(_config.getProperty(PROP_USE_OPENTRACKERS, DEFAULT_USE_OPENTRACKERS)).booleanValue();
}
private int getStartupDelayMinutes() { return 1; }
public File getDataDir() {
String dir = _config.getProperty(PROP_DIR);
@@ -105,6 +117,12 @@ public class SnarkManager implements Snark.CompleteListener {
_config.setProperty(PROP_EEP_PORT, "4444");
if (!_config.containsKey(PROP_UPLOADERS_TOTAL))
_config.setProperty(PROP_UPLOADERS_TOTAL, "" + Snark.MAX_TOTAL_UPLOADERS);
if (!_config.containsKey(PROP_UPBW_MAX)) {
if (_context instanceof RouterContext)
_config.setProperty(PROP_UPBW_MAX, "" + (((RouterContext)_context).bandwidthLimiter().getOutboundKBytesPerSecond() / 3));
else
_config.setProperty(PROP_UPBW_MAX, "" + DEFAULT_MAX_UP_BW);
}
if (!_config.containsKey(PROP_DIR))
_config.setProperty(PROP_DIR, "i2psnark");
if (!_config.containsKey(PROP_AUTO_START))
@@ -136,6 +154,7 @@ public class SnarkManager implements Snark.CompleteListener {
if (eepHost != null)
I2PSnarkUtil.instance().setProxy(eepHost, eepPort);
I2PSnarkUtil.instance().setMaxUploaders(getInt(PROP_UPLOADERS_TOTAL, Snark.MAX_TOTAL_UPLOADERS));
I2PSnarkUtil.instance().setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW));
getDataDir().mkdirs();
}
@@ -152,7 +171,7 @@ public class SnarkManager implements Snark.CompleteListener {
public void updateConfig(String dataDir, boolean autoStart, String seedPct, String eepHost,
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
String upLimit) {
String upLimit, String upBW, boolean useOpenTrackers, String openTrackers) {
boolean changed = false;
if (eepHost != null) {
int port = I2PSnarkUtil.instance().getEepProxyPort();
@@ -170,7 +189,7 @@ public class SnarkManager implements Snark.CompleteListener {
if (upLimit != null) {
int limit = I2PSnarkUtil.instance().getMaxUploaders();
try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {}
if ( limit != I2PSnarkUtil.instance().getEepProxyPort()) {
if ( limit != I2PSnarkUtil.instance().getMaxUploaders()) {
if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) {
I2PSnarkUtil.instance().setMaxUploaders(limit);
changed = true;
@@ -181,6 +200,20 @@ public class SnarkManager implements Snark.CompleteListener {
}
}
}
if (upBW != null) {
int limit = I2PSnarkUtil.instance().getMaxUpBW();
try { limit = Integer.parseInt(upBW); } catch (NumberFormatException nfe) {}
if ( limit != I2PSnarkUtil.instance().getMaxUpBW()) {
if ( limit >= MIN_UP_BW ) {
I2PSnarkUtil.instance().setMaxUpBW(limit);
changed = true;
_config.setProperty(PROP_UPBW_MAX, "" + limit);
addMessage("Up BW limit changed to " + limit + "KBps");
} else {
addMessage("Minimum Up BW limit is " + MIN_UP_BW + "KBps");
}
}
}
if (i2cpHost != null) {
int oldI2CPPort = I2PSnarkUtil.instance().getI2CPPort();
String oldI2CPHost = I2PSnarkUtil.instance().getI2CPHost();
@@ -265,6 +298,18 @@ public class SnarkManager implements Snark.CompleteListener {
addMessage("Adjusted autostart to " + autoStart);
changed = true;
}
if (shouldUseOpenTrackers() != useOpenTrackers) {
_config.setProperty(PROP_USE_OPENTRACKERS, useOpenTrackers + "");
addMessage((useOpenTrackers ? "En" : "Dis") + "abled open trackers - torrent restart required to take effect");
changed = true;
}
if (openTrackers != null) {
if (openTrackers.trim().length() > 0 && !openTrackers.trim().equals(getOpenTrackerString())) {
_config.setProperty(PROP_OPENTRACKERS, openTrackers.trim());
addMessage("Open Tracker list changed - torrent restart required to take effect");
changed = true;
}
}
if (changed) {
saveConfig();
} else {
@@ -595,11 +640,12 @@ public class SnarkManager implements Snark.CompleteListener {
private static final String DEFAULT_TRACKERS[] = {
"Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/"
, "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/"
, "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/"
// , "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/"
, "NickyB", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php=http://nickyb.i2p/bittorrent/"
, "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/"
, "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/"
// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/"
// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/"
// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php"
, "welterde", "http://BGKmlDOoH3RzFbPRfRpZV2FjpVj8~3moFftw5-dZfDf2070TOe8Tf2~DAVeaM6ZRLdmFEt~9wyFL8YMLMoLoiwGEH6IGW6rc45tstN68KsBDWZqkTohV1q9XFgK9JnCwE~Oi89xLBHsLMTHOabowWM6dkC8nI6QqJC2JODqLPIRfOVrDdkjLwtCrsckzLybNdFmgfoqF05UITDyczPsFVaHtpF1sRggOVmdvCM66otyonlzNcJbn59PA-R808vUrCPMGU~O9Wys0i-NoqtIbtWfOKnjCRFMNw5ex4n9m5Sxm9e20UkpKG6qzEuvKZWi8vTLe1NW~CBrj~vG7I3Ok4wybUFflBFOaBabxYJLlx4xTE1zJIVxlsekmAjckB4v-cQwulFeikR4LxPQ6mCQknW2HZ4JQIq6hL9AMabxjOlYnzh7kjOfRGkck8YgeozcyTvcDUcUsOuSTk06L4kdrv8h2Cozjbloi5zl6KTbj5ZTciKCxi73Pn9grICn-HQqEAAAA.i2p/a=http://tracker.welterde.i2p/stats?mode=top5"
};
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
@@ -634,6 +680,26 @@ public class SnarkManager implements Snark.CompleteListener {
return trackerMap;
}
public String getOpenTrackerString() {
return _config.getProperty(PROP_OPENTRACKERS, DEFAULT_OPENTRACKERS);
}
/** comma delimited list open trackers to use as backups */
/** sorted map of name to announceURL=baseURL */
public List getOpenTrackers() {
if (!shouldUseOpenTrackers())
return null;
List rv = new ArrayList(1);
String trackers = getOpenTrackerString();
StringTokenizer tok = new StringTokenizer(trackers, ", ");
while (tok.hasMoreTokens())
rv.add(tok.nextToken());
if (rv.size() <= 0)
return null;
return rv;
}
private static class TorrentFilenameFilter implements FilenameFilter {
private static final TorrentFilenameFilter _filter = new TorrentFilenameFilter();
public static TorrentFilenameFilter instance() { return _filter; }

View File

@@ -117,7 +117,8 @@ public class Storage
}
String name = baseFile.getName();
if (files.size() == 1)
if (files.size() == 1) // FIXME: ...and if base file not a directory or should this be the only check?
// this makes a bad metainfo if the directory has only one file in it
{
files = null;
lengthsList = null;
@@ -406,7 +407,7 @@ public class Storage
/**
* Removes 'suspicious' characters from the give file name.
*/
private String filterName(String name)
private static String filterName(String name)
{
// XXX - Is this enough?
return name.replace(File.separatorChar, '_');
@@ -438,7 +439,7 @@ public class Storage
return f;
}
private File getFileFromNames(File base, List names) throws IOException
public static File getFileFromNames(File base, List names)
{
Iterator it = names.iterator();
while (it.hasNext())

View File

@@ -46,6 +46,10 @@ public class TrackerClient extends I2PThread
private final static int SLEEP = 5; // 5 minutes.
private final static int DELAY_MIN = 2000; // 2 secs.
private final static int DELAY_MUL = 1500; // 1.5 secs.
private final static int MAX_REGISTER_FAILS = 10; // * INITIAL_SLEEP = 15m to register
private final static int INITIAL_SLEEP = 90*1000;
private final static int MAX_CONSEC_FAILS = 5; // slow down after this
private final static int LONG_SLEEP = 30*60*1000; // sleep a while after lots of fails
private final MetaInfo meta;
private final PeerCoordinator coordinator;
@@ -54,8 +58,7 @@ public class TrackerClient extends I2PThread
private boolean stop;
private boolean started;
private long interval;
private long lastRequestTime;
private List trackers;
public TrackerClient(MetaInfo meta, PeerCoordinator coordinator)
{
@@ -100,14 +103,47 @@ public class TrackerClient extends I2PThread
public void run()
{
// XXX - Support other IPs
String announce = meta.getAnnounce(); //I2PSnarkUtil.instance().rewriteAnnounce(meta.getAnnounce());
String infoHash = urlencode(meta.getInfoHash());
String peerID = urlencode(coordinator.getID());
_log.debug("Announce: [" + meta.getAnnounce() + "] infoHash: " + infoHash
+ " xmitAnnounce: [" + announce + "]");
_log.debug("Announce: [" + meta.getAnnounce() + "] infoHash: " + infoHash);
// Construct the list of trackers for this torrent,
// starting with the primary one listed in the metainfo,
// followed by the secondary open trackers
// It's painful, but try to make sure if an open tracker is also
// the primary tracker, that we don't add it twice.
trackers = new ArrayList(2);
trackers.add(new Tracker(meta.getAnnounce(), true));
List tlist = SnarkManager.instance().getOpenTrackers();
if (tlist != null) {
for (int i = 0; i < tlist.size(); i++) {
String url = (String)tlist.get(i);
if (!url.startsWith("http://")) {
_log.error("Bad announce URL: [" + url + "]");
continue;
}
int slash = url.indexOf('/', 7);
if (slash <= 7) {
_log.error("Bad announce URL: [" + url + "]");
continue;
}
if (meta.getAnnounce().startsWith(url.substring(0, slash)))
continue;
String dest = I2PSnarkUtil.instance().lookup(url.substring(7, slash));
if (dest == null) {
_log.error("Announce host unknown: [" + url + "]");
continue;
}
if (meta.getAnnounce().startsWith("http://" + dest))
continue;
if (meta.getAnnounce().startsWith("http://i2p/" + dest))
continue;
trackers.add(new Tracker(url, false));
_log.debug("Additional announce: [" + url + "] for infoHash: " + infoHash);
}
}
long uploaded = coordinator.getUploaded();
long downloaded = coordinator.getDownloaded();
long left = coordinator.getLeft();
@@ -119,78 +155,29 @@ public class TrackerClient extends I2PThread
{
if (!verifyConnected()) return;
boolean started = false;
while (!started)
{
sleptTime = 0;
try
{
// Send start.
TrackerInfo info = doRequest(announce, infoHash, peerID,
uploaded, downloaded, left,
STARTED_EVENT);
Set peers = info.getPeers();
coordinator.trackerSeenPeers = peers.size();
coordinator.trackerProblems = null;
if (!completed) {
Iterator it = peers.iterator();
while (it.hasNext()) {
Peer cur = (Peer)it.next();
coordinator.addPeer(cur);
int delay = DELAY_MUL;
delay *= ((int)cur.getPeerID().getAddress().calculateHash().toBase64().charAt(0)) % 10;
delay += DELAY_MIN;
sleptTime += delay;
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
}
}
started = true;
}
catch (IOException ioe)
{
// Probably not fatal (if it doesn't last to long...)
Snark.debug
("WARNING: Could not contact tracker at '"
+ announce + "': " + ioe, Snark.WARNING);
coordinator.trackerProblems = ioe.getMessage();
if (coordinator.trackerProblems.toLowerCase().startsWith(NOT_REGISTERED)) {
stop = true;
coordinator.snark.stopTorrent();
}
}
if (stop)
break;
if (!started)
{
Snark.debug(" Retrying in one minute...", Snark.DEBUG);
try
{
// Sleep one minutes...
Thread.sleep(60*1000);
}
catch(InterruptedException interrupt)
{
// ignore
}
}
}
boolean firstTime = true;
int consecutiveFails = 0;
Random r = new Random();
while(!stop)
{
try
{
// Sleep some minutes...
// Sleep the minimum interval for all the trackers, but 60s minimum
// except for the first time...
int delay;
if(coordinator.trackerProblems != null && !completed) {
delay = 60*1000;
} else if(completed) {
delay = 3*SLEEP*60*1000 + r.nextInt(120*1000);
} else {
delay = SLEEP*60*1000 + r.nextInt(120*1000);
delay -= sleptTime;
}
int random = r.nextInt(120*1000);
if (firstTime) {
delay = r.nextInt(30*1000);
firstTime = false;
} else if (completed && started)
delay = 3*SLEEP*60*1000 + random;
else if (coordinator.trackerProblems != null && ++consecutiveFails < MAX_CONSEC_FAILS)
delay = INITIAL_SLEEP;
else
// sleep a while, when we wake up we will contact only the trackers whose intervals have passed
delay = SLEEP*60*1000 + random;
if (delay > 0)
Thread.sleep(delay);
}
@@ -218,21 +205,37 @@ public class TrackerClient extends I2PThread
else
event = NO_EVENT;
// *** loop once for each tracker
// Only do a request when necessary.
sleptTime = 0;
if (event == COMPLETED_EVENT
|| coordinator.needPeers()
|| System.currentTimeMillis() > lastRequestTime + interval)
int maxSeenPeers = 0;
for (Iterator iter = trackers.iterator(); iter.hasNext(); ) {
Tracker tr = (Tracker)iter.next();
if ((!stop) && (!tr.stop) &&
(completed || coordinator.needPeers()) &&
(event == COMPLETED_EVENT || System.currentTimeMillis() > tr.lastRequestTime + tr.interval))
{
try
{
TrackerInfo info = doRequest(announce, infoHash, peerID,
if (!tr.started)
event = STARTED_EVENT;
TrackerInfo info = doRequest(tr, infoHash, peerID,
uploaded, downloaded, left,
event);
coordinator.trackerProblems = null;
tr.trackerProblems = null;
tr.registerFails = 0;
tr.consecutiveFails = 0;
if (tr.isPrimary)
consecutiveFails = 0;
started = true;
tr.started = true;
Set peers = info.getPeers();
coordinator.trackerSeenPeers = peers.size();
tr.seenPeers = peers.size();
if (coordinator.trackerSeenPeers < tr.seenPeers) // update rising number quickly
coordinator.trackerSeenPeers = tr.seenPeers;
if ( (left > 0) && (!completed) ) {
// we only want to talk to new people if we need things
// from them (duh)
@@ -257,16 +260,38 @@ public class TrackerClient extends I2PThread
// Probably not fatal (if it doesn't last to long...)
Snark.debug
("WARNING: Could not contact tracker at '"
+ announce + "': " + ioe, Snark.WARNING);
coordinator.trackerProblems = ioe.getMessage();
if (coordinator.trackerProblems.toLowerCase().startsWith(NOT_REGISTERED)) {
stop = true;
coordinator.snark.stopTorrent();
+ tr.announce + "': " + ioe, Snark.WARNING);
tr.trackerProblems = ioe.getMessage();
// don't show secondary tracker problems to the user
if (tr.isPrimary)
coordinator.trackerProblems = tr.trackerProblems;
if (tr.trackerProblems.toLowerCase().startsWith(NOT_REGISTERED)) {
// Give a guy some time to register it if using opentrackers too
if (trackers.size() == 1) {
stop = true;
coordinator.snark.stopTorrent();
} else { // hopefully each on the opentrackers list is really open
if (tr.registerFails++ > MAX_REGISTER_FAILS)
tr.stop = true;
}
}
if (++tr.consecutiveFails == MAX_CONSEC_FAILS) {
tr.seenPeers = 0;
if (tr.interval < LONG_SLEEP)
tr.interval = LONG_SLEEP; // slow down
}
}
}
}
}
if ((!tr.stop) && maxSeenPeers < tr.seenPeers)
maxSeenPeers = tr.seenPeers;
} // *** end of trackers loop here
// we could try and total the unique peers but that's too hard for now
coordinator.trackerSeenPeers = maxSeenPeers;
if (!started)
Snark.debug(" Retrying in one minute...", Snark.DEBUG);
} // *** end of while loop
} // try
catch (Throwable t)
{
I2PSnarkUtil.instance().debug("TrackerClient: " + t, Snark.ERROR, t);
@@ -277,21 +302,27 @@ public class TrackerClient extends I2PThread
{
try
{
if (!verifyConnected()) return;
TrackerInfo info = doRequest(announce, infoHash, peerID, uploaded,
// try to contact everybody we can
// We don't need I2CP connection for eepget
// if (!verifyConnected()) return;
for (Iterator iter = trackers.iterator(); iter.hasNext(); ) {
Tracker tr = (Tracker)iter.next();
if (tr.started && (!tr.stop) && tr.trackerProblems == null)
doRequest(tr, infoHash, peerID, uploaded,
downloaded, left, STOPPED_EVENT);
}
}
catch(IOException ioe) { /* ignored */ }
}
}
private TrackerInfo doRequest(String announce, String infoHash,
private TrackerInfo doRequest(Tracker tr, String infoHash,
String peerID, long uploaded,
long downloaded, long left, String event)
throws IOException
{
String s = announce
String s = tr.announce
+ "?info_hash=" + infoHash
+ "&peer_id=" + peerID
+ "&port=" + port
@@ -300,9 +331,9 @@ public class TrackerClient extends I2PThread
+ "&downloaded=" + downloaded
+ "&left=" + left
+ ((event != NO_EVENT) ? ("&event=" + event) : "");
if (Snark.debug >= Snark.INFO)
Snark.debug("Sending TrackerClient request: " + s, Snark.INFO);
Snark.debug("Sending TrackerClient request: " + s, Snark.INFO);
tr.lastRequestTime = System.currentTimeMillis();
File fetched = I2PSnarkUtil.instance().get(s);
if (fetched == null) {
throw new IOException("Error fetching " + s);
@@ -315,15 +346,13 @@ public class TrackerClient extends I2PThread
TrackerInfo info = new TrackerInfo(in, coordinator.getID(),
coordinator.getMetaInfo());
if (Snark.debug >= Snark.INFO)
Snark.debug("TrackerClient response: " + info, Snark.INFO);
lastRequestTime = System.currentTimeMillis();
Snark.debug("TrackerClient response: " + info, Snark.INFO);
String failure = info.getFailureReason();
if (failure != null)
throw new IOException(failure);
interval = info.getInterval() * 1000;
tr.interval = info.getInterval() * 1000;
return info;
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
@@ -349,4 +378,32 @@ public class TrackerClient extends I2PThread
return sb.toString();
}
private class Tracker
{
String announce;
boolean isPrimary;
long interval;
long lastRequestTime;
String trackerProblems;
boolean stop;
boolean started;
int registerFails;
int consecutiveFails;
int seenPeers;
public Tracker(String a, boolean p)
{
announce = a;
isPrimary = p;
interval = INITIAL_SLEEP;
lastRequestTime = 0;
trackerProblems = null;
stop = false;
started = false;
registerFails = 0;
consecutiveFails = 0;
seenPeers = 0;
}
}
}

View File

@@ -107,13 +107,17 @@ public class I2PSnarkServlet extends HttpServlet {
if (I2PSnarkUtil.instance().connected())
out.write("<a href=\"" + uri + "?action=StopAll&nonce=" + _nonce +
"\" title=\"Stop all torrents and the i2p tunnel\">Stop All</a>");
else if (snarks.size() > 0)
out.write("<a href=\"" + uri + "?action=StartAll&nonce=" + _nonce +
"\" title=\"Start all torrents and the i2p tunnel\">Start All</a>");
else
out.write("&nbsp;");
out.write("</th></tr></thead>\n");
for (int i = 0; i < snarks.size(); i++) {
Snark snark = (Snark)snarks.get(i);
boolean showPeers = "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam);
displaySnark(out, snark, uri, i, stats, showPeers);
boolean showDebug = "2".equals(peerParam);
boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam);
displaySnark(out, snark, uri, i, stats, showPeers, showDebug);
}
if (snarks.size() <= 0) {
out.write(TABLE_EMPTY);
@@ -248,23 +252,31 @@ public class I2PSnarkServlet extends HttpServlet {
_manager.addMessage("Torrent file deleted: " + f.getAbsolutePath());
List files = snark.meta.getFiles();
String dataFile = snark.meta.getName();
for (int i = 0; files != null && i < files.size(); i++) {
// multifile torrents have the getFiles() return lists of lists of filenames, but
// each of those lists just contain a single file afaict...
File df = new File(_manager.getDataDir(), files.get(i).toString());
boolean deleted = FileUtil.rmdir(df, false);
if (deleted)
_manager.addMessage("Data dir deleted: " + df.getAbsolutePath());
else
_manager.addMessage("Data dir could not be deleted: " + df.getAbsolutePath());
}
if (dataFile != null) {
f = new File(_manager.getDataDir(), dataFile);
boolean deleted = f.delete();
if (deleted)
f = new File(_manager.getDataDir(), dataFile);
if (files == null) { // single file torrent
if (f.delete())
_manager.addMessage("Data file deleted: " + f.getAbsolutePath());
else
_manager.addMessage("Data file could not be deleted: " + f.getAbsolutePath());
break;
}
for (int i = 0; i < files.size(); i++) { // pass 1 delete files
// multifile torrents have the getFiles() return lists of lists of filenames, but
// each of those lists just contain a single file afaict...
File df = Storage.getFileFromNames(f, (List) files.get(i));
if (df.delete())
_manager.addMessage("Data file deleted: " + df.getAbsolutePath());
else
_manager.addMessage("Data file could not be deleted: " + df.getAbsolutePath());
}
for (int i = files.size() - 1; i >= 0; i--) { // pass 2 delete dirs - not foolproof,
// we could sort and do a strict bottom-up
File df = Storage.getFileFromNames(f, (List) files.get(i));
df = df.getParentFile();
if (df == null || !df.exists())
continue;
if(df.delete())
_manager.addMessage("Data dir deleted: " + df.getAbsolutePath());
}
break;
}
@@ -281,7 +293,10 @@ public class I2PSnarkServlet extends HttpServlet {
String i2cpPort = req.getParameter("i2cpPort");
String i2cpOpts = req.getParameter("i2cpOpts");
String upLimit = req.getParameter("upLimit");
_manager.updateConfig(dataDir, autoStart, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts, upLimit);
String upBW = req.getParameter("upBW");
boolean useOpenTrackers = req.getParameter("useOpenTrackers") != null;
String openTrackers = req.getParameter("openTrackers");
_manager.updateConfig(dataDir, autoStart, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts, upLimit, upBW, useOpenTrackers, openTrackers);
} else if ("Create torrent".equals(action)) {
String baseData = req.getParameter("baseFile");
if (baseData != null) {
@@ -297,16 +312,19 @@ public class I2PSnarkServlet extends HttpServlet {
try {
Storage s = new Storage(baseFile, announceURL, null);
s.create();
s.close(); // close the files... maybe need a way to pass this Storage to addTorrent rather than starting over
MetaInfo info = s.getMetaInfo();
File torrentFile = new File(baseFile.getParent(), baseFile.getName() + ".torrent");
if (torrentFile.exists())
throw new IOException("Cannot overwrite an existing .torrent file: " + torrentFile.getPath());
_manager.saveTorrentStatus(info, s.getBitField()); // so addTorrent won't recheck
// DirMonitor could grab this first, maybe hold _snarks lock?
FileOutputStream out = new FileOutputStream(torrentFile);
out.write(info.getTorrentData());
out.close();
_manager.addMessage("Torrent created for " + baseFile.getName() + ": " + torrentFile.getAbsolutePath());
// now fire it up, but don't automatically seed it
_manager.addTorrent(torrentFile.getCanonicalPath(), false);
_manager.addTorrent(torrentFile.getCanonicalPath(), true);
_manager.addMessage("Many I2P trackers require you to register new torrents before seeding - please do so before starting " + baseFile.getName());
} catch (IOException ioe) {
_manager.addMessage("Error creating a torrent for " + baseFile.getAbsolutePath() + ": " + ioe.getMessage());
@@ -327,6 +345,14 @@ public class I2PSnarkServlet extends HttpServlet {
I2PSnarkUtil.instance().disconnect();
_manager.addMessage("I2P tunnel closed");
}
} else if ("StartAll".equals(action)) {
_manager.addMessage("Opening the I2P tunnel and starting all torrents");
List snarks = getSortedSnarks(req);
for (int i = 0; i < snarks.size(); i++) {
Snark snark = (Snark)snarks.get(i);
if (snark.stopped)
snark.startTorrent();
}
}
}
@@ -345,7 +371,7 @@ public class I2PSnarkServlet extends HttpServlet {
private static final int MAX_DISPLAYED_FILENAME_LENGTH = 60;
private static final int MAX_DISPLAYED_ERROR_LENGTH = 40;
private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers) throws IOException {
private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers, boolean showDebug) throws IOException {
String filename = snark.torrent;
File f = new File(filename);
filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name
@@ -529,6 +555,8 @@ public class I2PSnarkServlet extends HttpServlet {
else
client = "Unknown";
out.write("<font size=-1>" + client + "</font>&nbsp;&nbsp;<tt>" + peer.toString().substring(5, 9) + "</tt>");
if (showDebug)
out.write(" inactive " + (peer.getInactiveTime() / 1000) + "s");
out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
out.write("</td>\n\t");
@@ -577,6 +605,8 @@ public class I2PSnarkServlet extends HttpServlet {
out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
out.write("</td></tr>\n\t");
if (showDebug)
out.write("<tr><td colspan=\"8\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">" + peer.getSocket() + "</td></tr>");
}
}
}
@@ -638,6 +668,8 @@ public class I2PSnarkServlet extends HttpServlet {
String uri = req.getRequestURI();
String dataDir = _manager.getDataDir().getAbsolutePath();
boolean autoStart = _manager.shouldAutoStart();
boolean useOpenTrackers = _manager.shouldUseOpenTrackers();
String openTrackers = _manager.getOpenTrackerString();
//int seedPct = 0;
out.write("<form action=\"" + uri + "\" method=\"POST\">\n");
@@ -669,17 +701,25 @@ public class I2PSnarkServlet extends HttpServlet {
out.write("</select><br />\n");
*/
out.write("Total uploader limit: <input type=\"text\" name=\"upLimit\" value=\""
+ I2PSnarkUtil.instance().getMaxUploaders() + "\" size=\"3\" /> peers<br />\n");
+ I2PSnarkUtil.instance().getMaxUploaders() + "\" size=\"3\" maxlength=\"3\" /> peers<br />\n");
out.write("Up bandwidth limit: <input type=\"text\" name=\"upBW\" value=\""
+ I2PSnarkUtil.instance().getMaxUpBW() + "\" size=\"3\" maxlength=\"3\" /> KBps <i>(Router Up BW / 3 recommended)</i><br />\n");
out.write("Use open trackers also: <input type=\"checkbox\" name=\"useOpenTrackers\" value=\"true\" "
+ (useOpenTrackers ? "checked " : "")
+ "title=\"If true, uses open trackers in addition\" /> ");
out.write("Announce URLs: <input type=\"text\" name=\"openTrackers\" value=\""
+ openTrackers + "\" size=\"50\" /><br />\n");
//out.write("<hr />\n");
out.write("EepProxy host: <input type=\"text\" name=\"eepHost\" value=\""
+ I2PSnarkUtil.instance().getEepProxyHost() + "\" size=\"15\" /> ");
out.write("port: <input type=\"text\" name=\"eepPort\" value=\""
+ I2PSnarkUtil.instance().getEepProxyPort() + "\" size=\"5\" /><br />\n");
+ I2PSnarkUtil.instance().getEepProxyPort() + "\" size=\"5\" maxlength=\"5\" /><br />\n");
out.write("I2CP host: <input type=\"text\" name=\"i2cpHost\" value=\""
+ I2PSnarkUtil.instance().getI2CPHost() + "\" size=\"15\" /> ");
out.write("port: <input type=\"text\" name=\"i2cpPort\" value=\"" +
+ I2PSnarkUtil.instance().getI2CPPort() + "\" size=\"5\" /> <br />\n");
+ I2PSnarkUtil.instance().getI2CPPort() + "\" size=\"5\" maxlength=\"5\" /> <br />\n");
StringBuffer opts = new StringBuffer(64);
Map options = new TreeMap(I2PSnarkUtil.instance().getI2CPOptions());
for (Iterator iter = options.keySet().iterator(); iter.hasNext(); ) {
@@ -813,7 +853,8 @@ class FetchAndAdd implements Runnable {
}
public void run() {
_url = _url.trim();
File file = I2PSnarkUtil.instance().get(_url, false);
// 3 retries
File file = I2PSnarkUtil.instance().get(_url, false, 3);
try {
if ( (file != null) && (file.exists()) && (file.length() > 0) ) {
_manager.addMessage("Torrent fetched from " + _url);

View File

@@ -122,6 +122,25 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
"The I2P HTTP Proxy supports http:// requests ONLY. Other protocols such as https:// and ftp:// are not allowed.<BR>")
.getBytes();
private final static byte[] ERR_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"+
"\r\n"+
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>"+
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>")
.getBytes();
private final static int MAX_POSTBYTES = 20*1024*1024; // arbitrary but huge - all in memory, no temp file
private final static byte[] ERR_MAXPOST =
("HTTP/1.1 503 Bad POST\r\n"+
"Content-Type: text/html; charset=iso-8859-1\r\n"+
"Cache-control: no-cache\r\n"+
"\r\n"+
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>"+
"The maximum POST size is " + MAX_POSTBYTES + " bytes.<BR>")
.getBytes();
/** used to assign unique IDs to the threads / clients. no logic or functionality */
private static volatile long __clientId = 0;
@@ -394,6 +413,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
usingWWWProxy = true;
if (_log.shouldLog(Log.DEBUG))
_log.debug(getPrefix(requestId) + "Host doesnt end with .i2p and it contains a period [" + host + "]: wwwProxy!");
} else if (host.toLowerCase().startsWith("localhost:")) {
if (out != null) {
out.write(ERR_LOCALHOST);
out.write("<p /><i>Generated on: ".getBytes());
out.write(new Date().toString().getBytes());
out.write("</i></body></html>\n".getBytes());
out.flush();
}
s.close();
return;
} else {
request = request.substring(pos + 1);
pos = request.indexOf("/");
@@ -484,12 +513,25 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
if (_log.shouldLog(Log.DEBUG))
_log.debug(getPrefix(requestId) + "NewRequest header: [" + newRequest.toString() + "]");
int postbytes = 0;
while (br.ready()) { // empty the buffer (POST requests)
int i = br.read();
if (i != -1) {
newRequest.append((char) i);
if (++postbytes > MAX_POSTBYTES) {
if (out != null) {
out.write(ERR_MAXPOST);
out.write("<p /><i>Generated on: ".getBytes());
out.write(new Date().toString().getBytes());
out.write("</i></body></html>\n".getBytes());
out.flush();
}
s.close();
return;
}
}
}
if (method == null || destination == null) {
l.log("No HTTP method found in the request.");
if (out != null) {
@@ -559,6 +601,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
l.log(ex.getMessage());
handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
closeSocket(s);
} catch (OutOfMemoryError oom) { // mainly for huge POSTs
IOException ex = new IOException("OOM (in POST?)");
_log.info("getPrefix(requestId) + Error trying to connect", ex);
l.log(ex.getMessage());
handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, currentProxy, requestId);
closeSocket(s);
}
}
@@ -597,7 +645,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
}
}
private static String jumpServers[] = {"http://orion.i2p/jump/",
private static String jumpServers[] = {
"http://i2host.i2p/cgi-bin/i2hostjump?",
// "http://orion.i2p/jump/",
"http://stats.i2p/cgi-bin/jump.cgi?a=",
"http://trevorreznik.i2p/cgi-bin/jump.php?hostname="
};
private static void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,

View File

@@ -164,7 +164,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
if (_log.shouldLog(Log.INFO))
_log.info("inbound: "+outmsg);
}
outmsg=outmsg+"\n";
outmsg=outmsg+"\r\n"; // rfc1459 sec. 2.3
output.write(outmsg.getBytes("ISO-8859-1"));
} else {
if (_log.shouldLog(Log.WARN))
@@ -238,7 +238,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
if (_log.shouldLog(Log.INFO))
_log.info("outbound: "+outmsg);
}
outmsg=outmsg+"\n";
outmsg=outmsg+"\r\n"; // rfc1459 sec. 2.3
output.write(outmsg.getBytes("ISO-8859-1"));
} else {
if (_log.shouldLog(Log.WARN))
@@ -272,7 +272,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
int idx=0;
final String[] allowedCommands =
{
"NOTICE",
// "NOTICE", // can contain CTCP
//"PING",
//"PONG",
"MODE",
@@ -306,34 +306,36 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
} catch(NumberFormatException nfe){}
if ("PING".equals(command))
if ("PING".equalsIgnoreCase(command))
return "PING 127.0.0.1"; // no way to know what the ircd to i2ptunnel server con is, so localhost works
if ("PONG".equals(command)) {
if ("PONG".equalsIgnoreCase(command)) {
// Turn the received ":irc.freshcoffee.i2p PONG irc.freshcoffee.i2p :127.0.0.1"
// into ":127.0.0.1 PONG 127.0.0.1 " so that the caller can append the client's extra parameter
// though, does 127.0.0.1 work for irc clients connecting remotely? and for all of them? sure would
// be great if irc clients actually followed the RFCs here, but i guess thats too much to ask.
// If we haven't PINGed them, or the PING we sent isn't something we know how to filter, this
// is blank.
String pong = expectedPong.length() > 0 ? expectedPong.toString() : null;
//
// String pong = expectedPong.length() > 0 ? expectedPong.toString() : null;
// If we aren't going to rewrite it, pass it through
String pong = expectedPong.length() > 0 ? expectedPong.toString() : s;
expectedPong.setLength(0);
return pong;
}
// Allow all allowedCommands
for(int i=0;i<allowedCommands.length;i++) {
if(allowedCommands[i].equals(command))
if(allowedCommands[i].equalsIgnoreCase(command))
return s;
}
// Allow PRIVMSG, but block CTCP.
if("PRIVMSG".equals(command))
if("PRIVMSG".equalsIgnoreCase(command) || "NOTICE".equalsIgnoreCase(command))
{
String msg;
msg = field[idx++];
byte[] bytes = msg.getBytes();
if(bytes[1]==0x01)
if(msg.indexOf(0x01) >= 0) // CTCP marker ^A can be anywhere, not just immediately after the ':'
{
// CTCP
msg=msg.substring(2);
@@ -356,7 +358,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
String command;
final String[] allowedCommands =
{
"NOTICE",
// "NOTICE", // can contain CTCP
"MODE",
"JOIN",
"NICK",
@@ -387,7 +389,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
command = field[0].toUpperCase();
if ("PING".equals(command)) {
if ("PING".equalsIgnoreCase(command)) {
// Most clients just send a PING and are happy with any old PONG. Others,
// like BitchX, actually expect certain behavior. It sends two different pings:
// "PING :irc.freshcoffee.i2p" and "PING 1234567890 127.0.0.1" (where the IP is the proxy)
@@ -403,13 +405,15 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
expectedPong.setLength(0);
if (field.length == 1) { // PING
rv = "PING";
expectedPong.append("PONG 127.0.0.1");
// If we aren't rewriting the PING don't rewrite the PONG
// expectedPong.append("PONG 127.0.0.1");
} else if (field.length == 2) { // PING nonce
rv = "PING " + field[1];
expectedPong.append("PONG ").append(field[1]);
// If we aren't rewriting the PING don't rewrite the PONG
// expectedPong.append("PONG ").append(field[1]);
} else if (field.length == 3) { // PING nonce serverLocation
rv = "PING " + field[1];
expectedPong.append("PONG ").append(field[1]);
expectedPong.append("PONG ").append(field[2]).append(" :").append(field[1]); // PONG serverLocation nonce
} else {
if (_log.shouldLog(Log.ERROR))
_log.error("IRC client sent a PING we don't understand, filtering it (\"" + s + "\")");
@@ -417,28 +421,37 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
}
if (_log.shouldLog(Log.WARN))
_log.warn("sending ping " + rv + ", waiting for " + expectedPong + " orig was [" + s + "]");
_log.warn("sending ping [" + rv + "], waiting for [" + expectedPong + "] orig was [" + s + "]");
return rv;
}
if ("PONG".equals(command))
if ("PONG".equalsIgnoreCase(command))
return "PONG 127.0.0.1"; // no way to know what the ircd to i2ptunnel server con is, so localhost works
// Allow all allowedCommands
for(int i=0;i<allowedCommands.length;i++)
{
if(allowedCommands[i].equals(command))
if(allowedCommands[i].equalsIgnoreCase(command))
return s;
}
// mIRC sends "NOTICE user :DCC Send file (IP)"
// in addition to the CTCP version
if("NOTICE".equalsIgnoreCase(command))
{
String msg = field[2];
if(msg.startsWith(":DCC "))
return null;
// fall through
}
// Allow PRIVMSG, but block CTCP (except ACTION).
if("PRIVMSG".equals(command))
if("PRIVMSG".equalsIgnoreCase(command) || "NOTICE".equalsIgnoreCase(command))
{
String msg;
msg = field[2];
byte[] bytes = msg.getBytes();
if(bytes[1]==0x01)
if(msg.indexOf(0x01) >= 0) // CTCP marker ^A can be anywhere, not just immediately after the ':'
{
// CTCP
msg=msg.substring(2);
@@ -451,14 +464,14 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
return s;
}
if("USER".equals(command)) {
if("USER".equalsIgnoreCase(command)) {
int idx = field[2].lastIndexOf(":");
if(idx<0)
return "USER user hostname localhost :realname";
String realname = field[2].substring(idx+1);
String ret = "USER "+field[1]+" hostname localhost :"+realname;
return ret;
} else if ("QUIT".equals(command)) {
} else if ("QUIT".equalsIgnoreCase(command)) {
return "QUIT :leaving";
}

View File

@@ -186,8 +186,9 @@
%><option value="0"<%=(tunnelDepth == 0 ? " selected=\"selected\"" : "") %>>0 hop tunnel (low anonymity, low latency)</option>
<option value="1"<%=(tunnelDepth == 1 ? " selected=\"selected\"" : "") %>>1 hop tunnel (medium anonymity, medium latency)</option>
<option value="2"<%=(tunnelDepth == 2 ? " selected=\"selected\"" : "") %>>2 hop tunnel (high anonymity, high latency)</option>
<% if (tunnelDepth > 2) {
%> <option value="<%=tunnelDepth%>" selected="selected"><%=tunnelDepth%> hop tunnel</option>
<option value="3"<%=(tunnelDepth == 3 ? " selected=\"selected\"" : "") %>>3 hop tunnel (very high anonymity, poor performance)</option>
<% if (tunnelDepth > 3) {
%> <option value="<%=tunnelDepth%>" selected="selected"><%=tunnelDepth%> hop tunnel (very poor performance)</option>
<% }
%></select>
</div>
@@ -213,11 +214,11 @@
</label>
<select id="tunnelQuantity" name="tunnelQuantity" title="Number of Tunnels in Group" class="selectbox">
<% int tunnelQuantity = editBean.getTunnelQuantity(curTunnel, 2);
%><option value="1"<%=(tunnelQuantity == 1 ? " selected=\"selected\"" : "") %>>1 inbound tunnel (low bandwidth usage, less reliability)</option>
<option value="2"<%=(tunnelQuantity == 2 ? " selected=\"selected\"" : "") %>>2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
<option value="3"<%=(tunnelQuantity == 3 ? " selected=\"selected\"" : "") %>>3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
%><option value="1"<%=(tunnelQuantity == 1 ? " selected=\"selected\"" : "") %>>1 inbound, 1 outbound tunnel (low bandwidth usage, less reliability)</option>
<option value="2"<%=(tunnelQuantity == 2 ? " selected=\"selected\"" : "") %>>2 inbound, 2 outbound tunnels (standard bandwidth usage, standard reliability)</option>
<option value="3"<%=(tunnelQuantity == 3 ? " selected=\"selected\"" : "") %>>3 inbound, 3 outbound tunnels (higher bandwidth usage, higher reliability)</option>
<% if (tunnelQuantity > 3) {
%> <option value="<%=tunnelQuantity%>" selected="selected"><%=tunnelQuantity%> inbound tunnels</option>
%> <option value="<%=tunnelQuantity%>" selected="selected"><%=tunnelQuantity%> tunnels</option>
<% }
%></select>
</div>
@@ -228,9 +229,9 @@
<select id="tunnelBackupQuantity" name="tunnelBackupQuantity" title="Number of Reserve Tunnels" class="selectbox">
<% int tunnelBackupQuantity = editBean.getTunnelBackupQuantity(curTunnel, 0);
%><option value="0"<%=(tunnelBackupQuantity == 0 ? " selected=\"selected\"" : "") %>>0 backup tunnels (0 redundancy, no added resource usage)</option>
<option value="1"<%=(tunnelBackupQuantity == 1 ? " selected=\"selected\"" : "") %>>1 backup tunnel (low redundancy, low resource usage)</option>
<option value="2"<%=(tunnelBackupQuantity == 2 ? " selected=\"selected\"" : "") %>>2 backup tunnels (medium redundancy, medium resource usage)</option>
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>>3 backup tunnels (high redundancy, high resource usage)</option>
<option value="1"<%=(tunnelBackupQuantity == 1 ? " selected=\"selected\"" : "") %>>1 backup tunnel each direction (low redundancy, low resource usage)</option>
<option value="2"<%=(tunnelBackupQuantity == 2 ? " selected=\"selected\"" : "") %>>2 backup tunnels each direction (medium redundancy, medium resource usage)</option>
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>>3 backup tunnels each direction (high redundancy, high resource usage)</option>
<% if (tunnelBackupQuantity > 3) {
%> <option value="<%=tunnelBackupQuantity%>" selected="selected"><%=tunnelBackupQuantity%> backup tunnels</option>
<% }
@@ -284,4 +285,4 @@
<div id="pageFooter">
</div>
</body>
</html>
</html>

View File

@@ -158,8 +158,9 @@
%><option value="0"<%=(tunnelDepth == 0 ? " selected=\"selected\"" : "") %>>0 hop tunnel (low anonymity, low latency)</option>
<option value="1"<%=(tunnelDepth == 1 ? " selected=\"selected\"" : "") %>>1 hop tunnel (medium anonymity, medium latency)</option>
<option value="2"<%=(tunnelDepth == 2 ? " selected=\"selected\"" : "") %>>2 hop tunnel (high anonymity, high latency)</option>
<% if (tunnelDepth > 2) {
%> <option value="<%=tunnelDepth%>" selected="selected"><%=tunnelDepth%> hop tunnel</option>
<option value="3"<%=(tunnelDepth == 3 ? " selected=\"selected\"" : "") %>>3 hop tunnel (very high anonymity, poor performance)</option>
<% if (tunnelDepth > 3) {
%> <option value="<%=tunnelDepth%>" selected="selected"><%=tunnelDepth%> hop tunnel (very poor performance)</option>
<% }
%></select>
</div>
@@ -185,11 +186,11 @@
</label>
<select id="tunnelQuantity" name="tunnelQuantity" title="Number of Tunnels in Group" class="selectbox">
<% int tunnelQuantity = editBean.getTunnelQuantity(curTunnel, 2);
%><option value="1"<%=(tunnelQuantity == 1 ? " selected=\"selected\"" : "") %>>1 inbound tunnel (low bandwidth usage, less reliability)</option>
<option value="2"<%=(tunnelQuantity == 2 ? " selected=\"selected\"" : "") %>>2 inbound tunnels (standard bandwidth usage, standard reliability)</option>
<option value="3"<%=(tunnelQuantity == 3 ? " selected=\"selected\"" : "") %>>3 inbound tunnels (higher bandwidth usage, higher reliability)</option>
%><option value="1"<%=(tunnelQuantity == 1 ? " selected=\"selected\"" : "") %>>1 inbound, 1 outbound tunnel (low bandwidth usage, less reliability)</option>
<option value="2"<%=(tunnelQuantity == 2 ? " selected=\"selected\"" : "") %>>2 inbound, 2 outbound tunnels (standard bandwidth usage, standard reliability)</option>
<option value="3"<%=(tunnelQuantity == 3 ? " selected=\"selected\"" : "") %>>3 inbound, 3 outbound tunnels (higher bandwidth usage, higher reliability)</option>
<% if (tunnelQuantity > 3) {
%> <option value="<%=tunnelQuantity%>" selected="selected"><%=tunnelQuantity%> inbound tunnels</option>
%> <option value="<%=tunnelQuantity%>" selected="selected"><%=tunnelQuantity%> tunnels</option>
<% }
%></select>
</div>
@@ -200,9 +201,9 @@
<select id="tunnelBackupQuantity" name="tunnelBackupQuantity" title="Number of Reserve Tunnels" class="selectbox">
<% int tunnelBackupQuantity = editBean.getTunnelBackupQuantity(curTunnel, 0);
%><option value="0"<%=(tunnelBackupQuantity == 0 ? " selected=\"selected\"" : "") %>>0 backup tunnels (0 redundancy, no added resource usage)</option>
<option value="1"<%=(tunnelBackupQuantity == 1 ? " selected=\"selected\"" : "") %>>1 backup tunnel (low redundancy, low resource usage)</option>
<option value="2"<%=(tunnelBackupQuantity == 2 ? " selected=\"selected\"" : "") %>>2 backup tunnels (medium redundancy, medium resource usage)</option>
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>>3 backup tunnels (high redundancy, high resource usage)</option>
<option value="1"<%=(tunnelBackupQuantity == 1 ? " selected=\"selected\"" : "") %>>1 backup tunnel each direction (low redundancy, low resource usage)</option>
<option value="2"<%=(tunnelBackupQuantity == 2 ? " selected=\"selected\"" : "") %>>2 backup tunnels each direction (medium redundancy, medium resource usage)</option>
<option value="3"<%=(tunnelBackupQuantity == 3 ? " selected=\"selected\"" : "") %>>3 backup tunnels each direction (high redundancy, high resource usage)</option>
<% if (tunnelBackupQuantity > 3) {
%> <option value="<%=tunnelBackupQuantity%>" selected="selected"><%=tunnelBackupQuantity%> backup tunnels</option>
<% }
@@ -256,4 +257,4 @@
<div id="pageFooter">
</div>
</body>
</html>
</html>

View File

@@ -1,21 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="all" name="jetty">
<property name="jetty.sha1" value="021164f84da7304bd1ff07c268b45aa3e0b13322" />
<property name="jetty.md5" value="a61adc832be6baf2678935506743cfc3" />
<property name="jetty.url" value="http://mesh.dl.sourceforge.net/sourceforge/jetty/jetty-5.1.12.zip" />
<property name="jetty.filename" value="jetty-5.1.12.zip" />
<target name="all" depends="build" />
<target name="fetchJettylib" >
<available property="jetty.available" file="jetty-5.1.12.zip" />
<ant target="doFetchJettylib" />
<target name="ensureJettylib" >
<available property="jetty.zip.available" file="${jetty.filename}" type="file" />
<available property="jetty.zip.extracted" file="jettylib" type="dir" />
<ant target="fetchJettylib" />
<ant target="verifyJettylib" />
<ant target="extractJettylib" />
</target>
<target name="doFetchJettylib" unless="jetty.available" >
<echo message="The libraries contained within the fetched file are from Jetty's 5.1.12" />
<echo message="distribution (http://jetty.mortbay.org/). These are not " />
<echo message="necessary for using I2P, but are used by some applications on top of I2P," />
<echo message="such as the routerconsole." />
<get src="http://mesh.dl.sourceforge.net/sourceforge/jetty/jetty-5.1.12.zip" verbose="true" dest="jetty-5.1.12.zip" />
<ant target="doExtract" />
<target name="fetchJettylib" unless="jetty.zip.available" >
<echo message="It seems that you don't have '${jetty.filename}' deployed." />
<echo message="The build script can download this file for you automatically," />
<echo message="or alternatively you can obtain it manually from:" />
<echo message="${jetty.url}" />
<echo message="" />
<echo message="The libraries contained in the fetched file provide the Jetty web server" />
<echo message="(http://jetty.mortbay.org/). They are not absolutely necessary" />
<echo message="but strongly recommended, since they are used by some applications" />
<echo message="on top of I2P, like the router console." />
<echo message="" />
<echo message="Even if you deploy the Jetty archive manually, the build script will" />
<echo message="still attempt to verify its checksums, which must be:" />
<echo message="SHA1 ${jetty.sha1}" />
<echo message="MD5 ${jetty.md5}" />
<echo message="" />
<input message="Download Jetty archive automatically?" validargs="y,n" addproperty="jetty.download" />
<fail message="Aborting as requested. Please deploy the Jetty archive manually." >
<condition>
<equals arg1="${jetty.download}" arg2="n"/>
</condition>
</fail>
<get src="${jetty.url}" verbose="true" dest="${jetty.filename}" />
</target>
<target name="doExtract">
<unzip src="jetty-5.1.12.zip" dest="." />
<target name="verifyJettylib" >
<condition property="jetty.zip.verified" >
<and>
<checksum file="${jetty.filename}" algorithm="SHA" property="${jetty.sha1}" />
<checksum file="${jetty.filename}" algorithm="MD5" property="${jetty.md5}" />
</and>
</condition>
<fail message="Jetty archive does not match its checksums!" >
<condition>
<not>
<istrue value="${jetty.zip.verified}" />
</not>
</condition>
</fail>
</target>
<target name="extractJettylib" unless="jetty.zip.extracted" >
<unzip src="${jetty.filename}" dest="." />
<mkdir dir="jettylib" />
<copy todir="jettylib">
<fileset dir="jetty-5.1.12/lib">
@@ -26,7 +69,7 @@
<fileset dir="jetty-5.1.12/ext">
<include name="ant.jar" />
<include name="commons-el.jar" />
<include name="commons-logging.jar" />
<include name="commons-logging.jar" />
<include name="jasper-compiler.jar" />
<include name="jasper-runtime.jar" />
<include name="javax.servlet.jar" />
@@ -36,7 +79,8 @@
</copy>
<delete dir="jetty-5.1.12" />
</target>
<target name="build" depends="fetchJettylib" />
<target name="build" depends="ensureJettylib" />
<target name="builddep" />
<target name="compile" />
<target name="jar" />

View File

@@ -138,8 +138,6 @@ public class I2PSocketManagerFactory {
I2PSession session = client.createSession(myPrivateKeyStream, opts);
session.connect();
I2PSocketManager sockMgr = createManager(session, opts, "manager");
if (sockMgr != null)
sockMgr.setDefaultOptions(sockMgr.buildOptions(opts));
return sockMgr;
} catch (I2PSessionException ise) {
_log.error("Error creating session for socket manager", ise);
@@ -199,4 +197,4 @@ public class I2PSocketManagerFactory {
}
return i2cpPort;
}
}
}

View File

@@ -164,7 +164,7 @@ public class ConfigNetHelper {
if (rate != null)
return rate;
else
return "16";
return "32";
}
public String getOutboundRate() {
String rate = _context.getProperty(PROP_OUTBOUND_KBPS);
@@ -178,7 +178,7 @@ public class ConfigNetHelper {
if (rate != null)
return rate;
else
return "32";
return "48";
}
public String getOutboundBurstRate() {
String rate = _context.getProperty(PROP_OUTBOUND_BURST_KBPS);
@@ -276,21 +276,21 @@ public class ConfigNetHelper {
}
public int getShareBandwidth() {
String irate = _context.getProperty(PROP_INBOUND_KBPS);
String orate = _context.getProperty(PROP_OUTBOUND_KBPS);
String pctStr = _context.getProperty(PROP_SHARE_PERCENTAGE);
String irate = _context.getProperty(PROP_INBOUND_KBPS, "32");
String orate = _context.getProperty(PROP_OUTBOUND_KBPS, "16");
String pctStr = _context.getProperty(PROP_SHARE_PERCENTAGE, "" + DEFAULT_SHARE_PERCENTAGE);
if ( (irate != null) && (orate != null) && (pctStr != null)) {
try {
int irateKBps = Integer.parseInt(irate);
int orateKBps = Integer.parseInt(orate);
if (irateKBps < 0 || orateKBps < 0)
return 0;
return 12;
int pct = Integer.parseInt(pctStr);
return (int) (((float) pct) * Math.min(irateKBps, orateKBps) / 100);
} catch (NumberFormatException nfe) {
// ignore
}
}
return 0;
return 12;
}
}

View File

@@ -20,11 +20,13 @@ public class ConfigStatsHandler extends FormHandler {
private String _graphs;
private boolean _explicitFilter;
private String _explicitFilterValue;
private boolean _isFull;
public ConfigStatsHandler() {
super();
_stats = new ArrayList();
_explicitFilter = false;
_isFull = false;
}
protected void processForm() {
@@ -70,6 +72,7 @@ public class ConfigStatsHandler extends FormHandler {
public void setExplicitFilter(String foo) { _explicitFilter = true; }
public void setExplicitFilterValue(String filter) { _explicitFilterValue = filter; }
public void setIsFull(String foo) { _isFull = true; }
/**
* The user made changes to the config and wants to save them, so
@@ -109,6 +112,7 @@ public class ConfigStatsHandler extends FormHandler {
_context.router().setConfigSetting(StatManager.PROP_STAT_FILTER, stats.toString());
_context.router().setConfigSetting("stat.summaries", _graphs);
_context.router().setConfigSetting(StatManager.PROP_STAT_FULL, "" + _isFull);
boolean ok = _context.router().saveConfig();
if (ok)
addFormNotice("Stat filter and location updated successfully to: " + stats.toString());

View File

@@ -10,6 +10,7 @@ import java.util.StringTokenizer;
import net.i2p.stat.Rate;
import net.i2p.stat.RateStat;
import net.i2p.stat.FrequencyStat;
import net.i2p.stat.StatManager;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
@@ -141,4 +142,10 @@ public class ConfigStatsHelper {
public boolean getCurrentIsGraphed() { return _currentIsGraphed; }
public boolean getCurrentCanBeGraphed() { return _currentCanBeGraphed; }
public String getExplicitFilter() { return _filter; }
public boolean getIsFull() {
String f = _context.getProperty(StatManager.PROP_STAT_FULL);
if (f != null && f.equals("true"))
return true;
return false;
}
}

View File

@@ -2,6 +2,7 @@ package net.i2p.router.web;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.crypto.TrustedUpdate;
import net.i2p.router.Router;
import net.i2p.router.web.ConfigServiceHandler.UpdateWrapperManagerTask;
import net.i2p.util.Log;
@@ -20,20 +21,29 @@ public class ConfigUpdateHandler extends FormHandler {
private String _trustedKeys;
public static final String PROP_NEWS_URL = "router.newsURL";
public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD";
// public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD";
public static final String DEFAULT_NEWS_URL = "http://complication.i2p/news.xml";
public static final String PROP_REFRESH_FREQUENCY = "router.newsRefreshFrequency";
public static final String DEFAULT_REFRESH_FREQUENCY = 12*60*60*1000 + "";
public static final String PROP_UPDATE_URL = "router.updateURL";
public static final String DEFAULT_UPDATE_URL = "http://dev.i2p.net/i2p/i2pupdate.sud";
public static final String PROP_UPDATE_POLICY = "router.updatePolicy";
public static final String DEFAULT_UPDATE_POLICY = "notify";
public static final String PROP_SHOULD_PROXY = "router.updateThroughProxy";
public static final String DEFAULT_SHOULD_PROXY = Boolean.FALSE.toString();
public static final String DEFAULT_SHOULD_PROXY = Boolean.TRUE.toString();
public static final String PROP_PROXY_HOST = "router.updateProxyHost";
public static final String DEFAULT_PROXY_HOST = "localhost";
public static final String PROP_PROXY_PORT = "router.updateProxyPort";
public static final String DEFAULT_PROXY_PORT = "4444";
public static final String PROP_UPDATE_URL = "router.updateURL";
// public static final String DEFAULT_UPDATE_URL = "http://dev.i2p.net/i2p/i2pupdate.sud";
public static final String DEFAULT_UPDATE_URL =
"http://amiga.i2p/i2p/i2pupdate.sud\r\n" +
"http://stats.i2p/i2p/i2pupdate.sud\r\n" +
"http://complication.i2p/i2p/i2pupdate.sud";
public static final String PROP_TRUSTED_KEYS = "router.trustedUpdateKeys";
protected void processForm() {
if ("Check for update now".equals(_action)) {
NewsFetcher fetcher = NewsFetcher.getInstance(I2PAppContext.getGlobalContext());
@@ -52,14 +62,6 @@ public class ConfigUpdateHandler extends FormHandler {
}
}
if ( (_updateURL != null) && (_updateURL.length() > 0) ) {
String oldURL = _context.router().getConfigSetting(PROP_UPDATE_URL);
if ( (oldURL == null) || (!_updateURL.equals(oldURL)) ) {
_context.router().setConfigSetting(PROP_UPDATE_URL, _updateURL);
addFormNotice("Updating update URL to " + _updateURL);
}
}
if ( (_proxyHost != null) && (_proxyHost.length() > 0) ) {
String oldHost = _context.router().getConfigSetting(PROP_PROXY_HOST);
if ( (oldHost == null) || (!_proxyHost.equals(oldHost)) ) {
@@ -98,8 +100,22 @@ public class ConfigUpdateHandler extends FormHandler {
addFormNotice("Updating update policy to " + _updatePolicy);
}
}
// should save the keys...
if ( (_updateURL != null) && (_updateURL.length() > 0) ) {
String oldURL = _context.router().getConfigSetting(PROP_UPDATE_URL);
if ( (oldURL == null) || (!_updateURL.equals(oldURL)) ) {
_context.router().setConfigSetting(PROP_UPDATE_URL, _updateURL);
addFormNotice("Updating update URLs.");
}
}
if ( (_trustedKeys != null) && (_trustedKeys.length() > 0) ) {
String oldKeys = new TrustedUpdate(_context).getTrustedKeysString();
if ( (oldKeys == null) || (!_trustedKeys.equals(oldKeys)) ) {
_context.router().setConfigSetting(PROP_TRUSTED_KEYS, _trustedKeys);
addFormNotice("Updating trusted keys.");
}
}
_context.router().saveConfig();
}

View File

@@ -1,6 +1,5 @@
package net.i2p.router.web;
import java.util.List;
import net.i2p.data.DataHelper;
import net.i2p.crypto.TrustedUpdate;
import net.i2p.router.RouterContext;
@@ -113,11 +112,6 @@ public class ConfigUpdateHelper {
}
public String getTrustedKeys() {
StringBuffer buf = new StringBuffer(1024);
TrustedUpdate up = new TrustedUpdate(_context);
List keys = up.getTrustedKeys();
for (int i = 0; i < keys.size(); i++)
buf.append((String)keys.get(i)).append('\n');
return buf.toString();
return new TrustedUpdate(_context).getTrustedKeysString();
}
}

View File

@@ -70,19 +70,32 @@ public class GraphHelper {
}
if (hasTx && hasRx && !_showEvents)
_out.write("<a href=\"viewstat.jsp?stat=bw.combined"
+ "&amp;periodCount=" + (3 * _periodCount )
+ "&amp;width=" + (3 * _width)
+ "&amp;height=" + (3 * _height)
+ "\" />");
_out.write("<img width=\""
+ (_width + 83) + "\" height=\"" + (_height + 92)
+ "\" src=\"viewstat.jsp?stat=bw.combined"
+ "&amp;periodCount=" + _periodCount
+ "&amp;width=" + _width
+ "&amp;height=" + (_height - 14)
+ "\" title=\"Combined bandwidth graph\" />\n");
+ "\" title=\"Combined bandwidth graph\" /></a>\n");
for (Iterator iter = ordered.iterator(); iter.hasNext(); ) {
SummaryListener lsnr = (SummaryListener)iter.next();
Rate r = lsnr.getRate();
String title = r.getRateStat().getName() + " for " + DataHelper.formatDuration(_periodCount * r.getPeriod());
_out.write("<img width=\""
_out.write("<a href=\"viewstat.jsp?stat="
+ r.getRateStat().getName()
+ "&amp;showEvents=" + _showEvents
+ "&amp;period=" + r.getPeriod()
+ "&amp;periodCount=" + (3 * _periodCount)
+ "&amp;width=" + (3 * _width)
+ "&amp;height=" + (3 * _height)
+ "\" />");
_out.write("<img border=\"0\" width=\""
+ (_width + 83) + "\" height=\"" + (_height + 92)
+ "\" src=\"viewstat.jsp?stat="
+ r.getRateStat().getName()
@@ -91,7 +104,7 @@ public class GraphHelper {
+ "&amp;periodCount=" + _periodCount
+ "&amp;width=" + _width
+ "&amp;height=" + _height
+ "\" title=\"" + title + "\" />\n");
+ "\" title=\"" + title + "\" /></a>\n");
}
if (_refreshDelaySeconds > 0)
_out.write("<meta http-equiv=\"refresh\" content=\"" + _refreshDelaySeconds + "\" />\n");

View File

@@ -24,6 +24,7 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
private Log _log;
private boolean _updateAvailable;
private long _lastFetch;
private String _lastModified;
private static NewsFetcher _instance;
//public static final synchronized NewsFetcher getInstance() { return _instance; }
public static final synchronized NewsFetcher getInstance(I2PAppContext ctx) {
@@ -40,14 +41,16 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
_context = ctx;
_log = ctx.logManager().getLog(NewsFetcher.class);
_instance = this;
_lastFetch = 0;
updateLastFetched();
}
private void updateLastFetched() {
File news = new File(NEWS_FILE);
if (news.exists())
_lastFetch = news.lastModified();
else
if (news.exists()) {
if (_lastFetch == 0)
_lastFetch = news.lastModified();
} else
_lastFetch = 0;
}
@@ -105,16 +108,15 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
proxyPort = Integer.parseInt(port);
EepGet get = null;
if (shouldProxy)
get = new EepGet(_context, proxyHost, proxyPort, 10, TEMP_NEWS_FILE, newsURL);
get = new EepGet(_context, true, proxyHost, proxyPort, 2, TEMP_NEWS_FILE, newsURL, true, null, _lastModified);
else
get = new EepGet(_context, 10, TEMP_NEWS_FILE, newsURL);
get = new EepGet(_context, false, null, 0, 0, TEMP_NEWS_FILE, newsURL, true, null, _lastModified);
get.addStatusListener(this);
get.fetch();
if (get.fetch())
_lastModified = get.getLastModified();
} catch (Throwable t) {
_log.error("Error fetching the news", t);
}
_lastFetch = _context.clock().now();
}
private static final String VERSION_STRING = "version=\"" + RouterVersion.VERSION + "\"";
@@ -207,22 +209,24 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
boolean copied = FileUtil.copy(TEMP_NEWS_FILE, NEWS_FILE, true);
if (copied) {
temp.delete();
checkForUpdates();
} else {
if (_log.shouldLog(Log.ERROR))
_log.error("Failed to copy the news file!");
}
} else {
if (_log.shouldLog(Log.ERROR))
_log.error("Transfer complete, but no file?");
if (_log.shouldLog(Log.WARN))
_log.warn("Transfer complete, but no file? - probably 304 Not Modified");
}
checkForUpdates();
_lastFetch = _context.clock().now();
}
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
if (_log.shouldLog(Log.ERROR))
_log.error("Failed to fetch the news from " + url);
if (_log.shouldLog(Log.WARN))
_log.warn("Failed to fetch the news from " + url);
File temp = new File(TEMP_NEWS_FILE);
temp.delete();
}
public void headerReceived(String url, int attemptNum, String key, String val) {}
public void attempting(String url) {}
}

View File

@@ -7,9 +7,13 @@ import java.io.OutputStream;
import java.net.Socket;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.router.RouterContext;
@@ -18,8 +22,8 @@ import net.i2p.util.I2PThread;
import net.i2p.util.EepGet;
/**
* Handler to deal with reseed requests. This reseed from the URL
* http://dev.i2p.net/i2pdb2/ unless the I2P configuration property "i2p.reseedURL" is
* Handler to deal with reseed requests. This will reseed from the URL
* http://i2pdb.tin0.de/netDb/ unless the I2P configuration property "i2p.reseedURL" is
* set. It always writes to ./netDb/, so don't mess with that.
*
*/
@@ -31,7 +35,7 @@ public class ReseedHandler {
// Reject unreasonably big files, because we download into a ByteArrayOutputStream.
private static final long MAX_RESEED_RESPONSE_SIZE = 8 * 1024 * 1024;
private static final String DEFAULT_SEED_URL = "http://dev.i2p.net/i2pdb2/";
private static final String DEFAULT_SEED_URL = "http://i2pdb.tin0.de/netDb/,http://netdb.i2p2.de/";
public ReseedHandler() {
this(ContextHelper.getContext(null));
@@ -107,6 +111,7 @@ public class ReseedHandler {
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {}
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {}
public void headerReceived(String url, int attemptNum, String key, String val) {}
public void attempting(String url) {}
// End of EepGet status listeners
/**
@@ -115,11 +120,33 @@ public class ReseedHandler {
* save them into this router's netDb dir.
*
*/
private static final String RESEED_TIPS =
"Ensure that nothing blocks outbound HTTP, check <a href=logs.jsp>logs</a> " +
"and if nothing helps, read FAQ about reseeding manually.";
private void reseed(boolean echoStatus) {
List URLList = new ArrayList();
String URLs = _context.getProperty("i2p.reseedURL", DEFAULT_SEED_URL);
StringTokenizer tok = new StringTokenizer(URLs, " ,");
while (tok.hasMoreTokens())
URLList.add(tok.nextToken().trim());
Collections.shuffle(URLList);
for (int i = 0; i < URLList.size() && _isRunning; i++)
reseedOne((String) URLList.get(i), echoStatus);
}
/**
* Fetch a directory listing and then all the routerInfo files in the listing.
* The listing must contain (exactly) strings that match:
* href="routerInfo-{hash}.dat">
* and then it fetches the files
* {seedURL}routerInfo-{hash}.dat
* after appending a '/' to seedURL if it doesn't have one.
* Essentially this means that the seedURL must be a directory, it
* can't end with 'index.html', for example.
**/
private void reseedOne(String seedURL, boolean echoStatus) {
String seedURL = _context.getProperty("i2p.reseedURL", DEFAULT_SEED_URL);
if ( (seedURL == null) || (seedURL.trim().length() <= 0) )
seedURL = DEFAULT_SEED_URL;
try {
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage","");
System.setProperty("net.i2p.router.web.ReseedHandler.statusMessage","Reseeding: fetching seed URL.");
@@ -128,8 +155,7 @@ public class ReseedHandler {
if (contentRaw == null) {
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
"Last reseed failed fully (failed reading seed URL). " +
"Ensure that nothing blocks outbound HTTP, check <a href=logs.jsp>logs</a> " +
"and if nothing helps, read FAQ about reseeding manually.");
RESEED_TIPS);
// Logging deprecated here since attemptFailed() provides better info
_log.debug("Failed reading seed URL: " + seedURL);
return;
@@ -151,8 +177,7 @@ public class ReseedHandler {
_log.error("Read " + contentRaw.length + " bytes from seed " + seedURL + ", but found no routerInfo URLs.");
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
"Last reseed failed fully (no routerInfo URLs at seed URL). " +
"Ensure that nothing blocks outbound HTTP, check <a href=logs.jsp>logs</a> " +
"and if nothing helps, read FAQ about reseeding manually.");
RESEED_TIPS);
return;
}
@@ -176,17 +201,28 @@ public class ReseedHandler {
}
}
if (echoStatus) System.out.println();
if (errors > 0) {
int failPercent = 100 * errors / urls.size();
// Less than 10% of failures is considered success,
// because some routerInfos will always fail.
if ((failPercent >= 10) && (failPercent < 90)) {
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
"Last reseed failed partly (" + errors + " of " + urls.size() + "). " +
"Ensure that nothing blocks outbound HTTP, check <a href=logs.jsp>logs</a> " +
"and if nothing helps, read FAQ about reseeding manually.");
"Last reseed failed partly (" + failPercent + "% of " + urls.size() + "). " +
RESEED_TIPS);
}
if (failPercent >= 90) {
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
"Last reseed failed (" + failPercent + "% of " + urls.size() + "). " +
RESEED_TIPS);
}
// Don't go on to the next URL if we have enough
if (fetched > 25)
_isRunning = false;
} catch (Throwable t) {
System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
"Last reseed failed fully (exception caught). " +
"Ensure that nothing blocks outbound HTTP, check <a href=logs.jsp>logs</a> " +
"and if nothing helps, read FAQ about reseeding manually.");
RESEED_TIPS);
_log.error("Error reseeding", t);
}
}

View File

@@ -2,6 +2,9 @@ package net.i2p.router.web;
import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.crypto.TrustedUpdate;
@@ -30,6 +33,7 @@ public class UpdateHandler {
private DecimalFormat _pct = new DecimalFormat("00.0%");
private static final String SIGNED_UPDATE_FILE = "i2pupdate.sud";
private static final String PROP_UPDATE_IN_PROGRESS = "net.i2p.router.web.UpdateHandler.updateInProgress";
public UpdateHandler() {
this(ContextHelper.getContext(null));
@@ -64,21 +68,27 @@ public class UpdateHandler {
}
public void update() {
// don't block waiting for the other one to finish
if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS, "false"))) {
_log.error("Update already running");
return;
}
synchronized (UpdateHandler.class) {
if (_updateRunner == null)
_updateRunner = new UpdateRunner();
if (_updateRunner.isRunning()) {
return;
} else {
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "true");
System.setProperty(PROP_UPDATE_IN_PROGRESS, "true");
I2PThread update = new I2PThread(_updateRunner, "Update");
update.start();
}
}
}
public String getStatus() {
if (_updateRunner == null)
return "";
return _updateRunner.getStatus();
}
@@ -86,23 +96,24 @@ public class UpdateHandler {
private boolean _isRunning;
private String _status;
private long _startedOn;
private long _written;
public UpdateRunner() {
_isRunning = false;
_status = "<b>Updating</b><br />";
_status = "<b>Updating</b>";
}
public boolean isRunning() { return _isRunning; }
public String getStatus() { return _status; }
public void run() {
_isRunning = true;
update();
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
_isRunning = false;
}
private void update() {
_startedOn = -1;
_status = "<b>Updating</b><br />";
String updateURL = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
_status = "<b>Updating</b>";
String updateURL = selectUpdateURL();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Selected update URL: " + updateURL);
boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT);
@@ -110,69 +121,89 @@ public class UpdateHandler {
try {
proxyPort = Integer.parseInt(port);
} catch (NumberFormatException nfe) {
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
return;
}
try {
EepGet get = null;
if (shouldProxy)
get = new EepGet(_context, proxyHost, proxyPort, 10, SIGNED_UPDATE_FILE, updateURL, false);
get = new EepGet(_context, proxyHost, proxyPort, 20, SIGNED_UPDATE_FILE, updateURL, false);
else
get = new EepGet(_context, 10, SIGNED_UPDATE_FILE, updateURL, false);
get = new EepGet(_context, 1, SIGNED_UPDATE_FILE, updateURL, false);
get.addStatusListener(UpdateRunner.this);
_startedOn = _context.clock().now();
get.fetch();
} catch (Throwable t) {
_context.logManager().getLog(UpdateHandler.class).error("Error updating", t);
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
}
}
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Attempt failed on " + url, cause);
_written = 0;
// ignored
}
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
_written += currentWrite;
StringBuffer buf = new StringBuffer(64);
buf.append("<b>Updating</b> ");
double pct = ((double)alreadyTransferred + (double)_written) / ((double)alreadyTransferred + (double)bytesRemaining);
double pct = ((double)alreadyTransferred + (double)currentWrite) /
((double)alreadyTransferred + (double)currentWrite + (double)bytesRemaining);
synchronized (_pct) {
buf.append(_pct.format(pct));
}
buf.append(":<br />\n").append(_written+alreadyTransferred);
buf.append(" transferred<br />");
buf.append(":<br />\n" + (currentWrite + alreadyTransferred));
buf.append(" transferred");
_status = buf.toString();
}
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
_status = "<b>Update downloaded</b><br />";
_status = "<b>Update downloaded</b>";
TrustedUpdate up = new TrustedUpdate(_context);
boolean ok = up.migrateVerified(RouterVersion.VERSION, SIGNED_UPDATE_FILE, "i2pupdate.zip");
File f = new File(SIGNED_UPDATE_FILE);
f.delete();
if (ok) {
_log.log(Log.CRIT, "Update was VERIFIED, restarting to install it");
_status = "<b>Update verified</b><br />Restarting<br />";
_status = "<b>Update verified</b><br />Restarting";
restart();
} else {
_log.log(Log.CRIT, "Update was INVALID - have you changed your keys?");
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
// One other possibility, the version in the file is not sufficient
// Perhaps need an int return code - but version problem unlikely?
_log.log(Log.CRIT, "Update was INVALID - signing key is not trusted or file is corrupt from " + url);
_status = "<b>Update signing key invalid or file is corrupt from " + url + "</b>";
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
}
}
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
_log.log(Log.CRIT, "Update did not download completely (" + bytesTransferred + " with "
_log.log(Log.CRIT, "Update from " + url + " did not download completely (" + bytesTransferred + " with "
+ bytesRemaining + " after " + currentAttempt + " tries)");
_status = "<b>Transfer failed</b><br />";
System.setProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false");
_status = "<b>Transfer failed</b>";
System.setProperty(PROP_UPDATE_IN_PROGRESS, "false");
}
public void headerReceived(String url, int attemptNum, String key, String val) {}
public void attempting(String url) {}
}
private void restart() {
_context.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
}
private String selectUpdateURL() {
String URLs = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_URL, ConfigUpdateHandler.DEFAULT_UPDATE_URL);
StringTokenizer tok = new StringTokenizer(URLs, " ,\r\n");
List URLList = new ArrayList();
while (tok.hasMoreTokens())
URLList.add(tok.nextToken().trim());
int size = URLList.size();
_log.log(Log.DEBUG, "Picking update source from " + size + " candidates.");
if (size <= 0) {
_log.log(Log.WARN, "Update list is empty - no update available");
return null;
}
int index = I2PAppContext.getGlobalContext().random().nextInt(size);
_log.log(Log.DEBUG, "Picked update source " + index + ".");
return (String) URLList.get(index);
}
}

View File

@@ -40,7 +40,8 @@
<input name="outboundburstrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="outboundBurstRate" />" /> KBps for
<jsp:getProperty name="nethelper" property="outboundBurstFactorBox" /><br />
<i>KBps = kilobytes per second = 1024 bytes per second.<br />
A negative rate means a default limit of 16KBytes per second.</i><br />
A negative inbound rate means a default limit of 32KBytes per second.
A negative outbound rate means a default limit of 16KBytes per second.</i><br />
Bandwidth share percentage:
<jsp:getProperty name="nethelper" property="sharePercentageBox" /><br />
<% int share = nethelper.getShareBandwidth();

View File

@@ -73,6 +73,10 @@ function toggleAll(category)
System.setProperty("net.i2p.router.web.ConfigStatsHandler.nonce", new java.util.Random().nextLong()+""); %>
<input type="hidden" name="action" value="foo" />
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigStatsHandler.nonce")%>" />
Enable full stats?
<input type="checkbox" name="isFull" value="true" <%
if (statshelper.getIsFull()) { %>checked="true" <% } %>/>
(change requires restart to take effect)<br />
Stat file: <input type="text" name="filename" value="<%=statshelper.getFilename()%>" /><br />
Filter: (<a href="javascript: void(null);" onclick="toggleAll('*')">toggle all</a>)<br />
<table>

View File

@@ -27,22 +27,26 @@
if (prev != null) System.setProperty("net.i2p.router.web.ConfigUpdateHandler.noncePrev", prev);
System.setProperty("net.i2p.router.web.ConfigUpdateHandler.nonce", new java.util.Random().nextLong()+""); %>
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigUpdateHandler.nonce")%>" />
<% if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"))) { %>
<i>Update In Progress</i><br /><br />
<% } else { %>
<input type="submit" name="action" value="Check for update now" /><br /><br />
<% } %>
News URL:
<input type="text" size="60" name="newsURL" value="<jsp:getProperty name="updatehelper" property="newsURL" />"><br />
Refresh frequency:
<jsp:getProperty name="updatehelper" property="refreshFrequencySelectBox" /><br />
Update URL:
<input type="text" size="60" name="updateURL" value="<jsp:getProperty name="updatehelper" property="updateURL" />"><br />
Update policy:
<jsp:getProperty name="updatehelper" property="updatePolicySelectBox" /><br />
Update through the eepProxy?
<p>Update through the eepProxy?
<jsp:getProperty name="updatehelper" property="updateThroughProxy" /><br />
eepProxy host: <input type="text" size="10" name="proxyHost" value="<jsp:getProperty name="updatehelper" property="proxyHost" />" /><br />
eepProxy port: <input type="text" size="4" name="proxyPort" value="<jsp:getProperty name="updatehelper" property="proxyPort" />" /><br />
<!-- prompt for the eepproxy -->
Trusted keys:
<textarea name="trustedKeys" disabled="true" cols="60" rows="2"><jsp:getProperty name="updatehelper" property="trustedKeys" /></textarea>
eepProxy port: <input type="text" size="4" name="proxyPort" value="<jsp:getProperty name="updatehelper" property="proxyPort" />" /></p>
<p>Update URLs:<br />
<textarea name="updateURL" cols="90" rows="4"><jsp:getProperty name="updatehelper" property="updateURL" /></textarea></p>
<p>Trusted keys:</br />
<textarea name="trustedKeys" cols="90" rows="4"><jsp:getProperty name="updatehelper" property="trustedKeys" /></textarea></p>
<br />
<input type="submit" name="action" value="Save" />
</form>
</div>

View File

@@ -34,7 +34,7 @@ Their XML parser requires the Sun XML APIs (JAXP) which is included in binary fo
by their binary code license. This product includes software developed by the Apache Software Foundation
(http://www.apache.org/). </p>
<p>Another application you can see on this webpage is <a href="http://www.i2p.net/i2ptunnel">I2PTunnel</a>
<p>Another application you can see on this webpage is <a href="http://www.i2p2.i2p/i2ptunnel">I2PTunnel</a>
(your <a href="i2ptunnel/" target="_blank">web interface</a>) - a GPL'ed application written by mihi that
lets you tunnel normal TCP/IP traffic over I2P (such as the eepproxy and the irc proxy). There is also a
<a href="http://susi.i2p/">susimail</a> web based mail client <a href="susimail/susimail">available</a> on
@@ -42,14 +42,14 @@ the console, which is a GPL'ed application written by susi23. The addressbook a
<a href="http://ragnarok.i2p/">Ragnarok</a> helps maintain your hosts.txt files (see ./addressbook/ for
more information).</p>
<p>The router by default also includes human's public domain <a href="http://www.i2p.net/sam">SAM</a> bridge,
<p>The router by default also includes human's public domain <a href="http://www.i2p2.i2p/sam">SAM</a> bridge,
which other client applications (such the <a href="http://duck.i2p/i2p-bt/">bittorrent port</a>) can use.
There is also an optimized library for doing large number calculations - jbigi - which in turn uses the
LGPL licensed <a href="http://swox.com/gmp/">GMP</a> library, tuned for various PC architectures. Launchers for windows users are built with <a href="http://launch4j.sourceforge.net/">Launch4J</a>, and the installer is built with <a href="http://www.izforge.com/izpack/">IzPack</a>. For
details on other applications available, as well as their licenses, please see the
<a href="http://www.i2p.net/licenses">license policy</a>. Source for the I2P code and most bundled
client applications can be found on our <a href="http://www.i2p.net/download">download page</a>, and is
in <a href="http://www.i2p.net/cvs">cvs</a>.</p>
<a href="http://www.i2p2.i2p/licenses">license policy</a>. Source for the I2P code and most bundled
client applications can be found on our <a href="http://www.i2p2.i2p/download">download page</a>.
.</p>
<h2>Release history</h2>
<jsp:useBean class="net.i2p.router.web.ContentHelper" id="contenthelper" scope="request" />
@@ -59,9 +59,8 @@ in <a href="http://www.i2p.net/cvs">cvs</a>.</p>
<jsp:getProperty name="contenthelper" property="textContent" />
<p>
A more complete list of updates can be found
<a href="http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/history.txt?rev=HEAD">online</a>
(<a href="http://dev.i2p/cgi-bin/cvsweb.cgi/i2p/history.txt?rev=HEAD">anonymously</a>)
A more complete list of changes can be found
in the history.txt file in your i2p directory.
</p>
</div>

View File

@@ -16,8 +16,9 @@
<b>Now:</b> <jsp:getProperty name="helper" property="time" /><!--<br />
<b>Status:</b> <a href="config.jsp"><jsp:getProperty name="helper" property="reachability" /></a>--><%
if (helper.updateAvailable()) {
// display all the time so we display the final failure message
out.print("<br />" + update.getStatus());
if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"))) {
out.print("<br />" + update.getStatus());
} else {
long nonce = new java.util.Random().nextLong();
String prev = System.getProperty("net.i2p.router.web.UpdateHandler.nonce");
@@ -39,7 +40,7 @@
<b>Active:</b> <jsp:getProperty name="helper" property="activePeers" />/<jsp:getProperty name="helper" property="activeProfiles" /><br />
<b>Fast:</b> <jsp:getProperty name="helper" property="fastPeers" /><br />
<b>High capacity:</b> <jsp:getProperty name="helper" property="highCapacityPeers" /><br />
<!-- <b>Well integrated:</b> <jsp:getProperty name="helper" property="wellIntegratedPeers" /><br /> -->
<b>Well integrated:</b> <jsp:getProperty name="helper" property="wellIntegratedPeers" /><br />
<b>Failing:</b> <jsp:getProperty name="helper" property="failingPeers" /><br />
<!-- <b>Shitlisted:</b> <jsp:getProperty name="helper" property="shitlistedPeers" /><br /> -->
<b>Known:</b> <jsp:getProperty name="helper" property="allPeers" /><br /><%

View File

@@ -112,12 +112,15 @@ public class SAMHandlerFactory {
case 1:
handler = new SAMv1Handler(s, verMajor, verMinor, i2cpProps);
break;
case 2:
handler = new SAMv2Handler(s, verMajor, verMinor, i2cpProps);
break;
default:
_log.error("BUG! Trying to initialize the wrong SAM version!");
throw new SAMException("BUG! (in handler instantiation)");
}
} catch (IOException e) {
_log.error("Error creating the v1 handler", e);
_log.error("Error creating the handler for version "+verMajor, e);
throw new SAMException("IOException caught during SAM handler instantiation");
}
return handler;
@@ -133,15 +136,16 @@ public class SAMHandlerFactory {
|| (maxMajor == -1) || (maxMinor == -1)) {
return null;
}
if (minMajor > maxMajor) {
return null;
} else if ((minMajor == maxMajor) && (minMinor > maxMinor)) {
return null;
}
if ((minMajor >= 1) && (minMinor >= 0)) {
return "1.0";
}
if ((minMinor >= 10) || (maxMinor >= 10)) return null ;
float fminVer = (float) minMajor + (float) minMinor / 10 ;
float fmaxVer = (float) maxMajor + (float) maxMinor / 10 ;
if ( ( fminVer <= 2.0 ) && ( fmaxVer >= 2.0 ) ) return "2.0" ;
if ( ( fminVer <= 1.0 ) && ( fmaxVer >= 1.0 ) ) return "1.0" ;
return null;
}

View File

@@ -15,14 +15,31 @@ import net.i2p.data.Destination;
/**
* Interface for sending streaming data to a SAM client
*/
public interface SAMStreamReceiver {
/**
* Sends the result of a stream send operation
*/
public void streamSendAnswer( int id, String result, String bufferState ) throws IOException;
/**
* Notifies that the outwards buffer is free for writing
*/
public void notifyStreamSendBufferFree( int id ) throws IOException;
/**
* Notify about a new incoming connection
*
* @param id New connection id
*/
public void notifyStreamConnection(int id, Destination dest) throws IOException;
public void notifyStreamIncomingConnection ( int id, Destination dest ) throws IOException;
/**
* Notify about a new outgoing connection
*
* @param id New connection id
*/
public void notifyStreamOutgoingConnection(int id, String result, String msg) throws IOException;
/**
* Send a byte array to a SAM client.

View File

@@ -47,13 +47,13 @@ public class SAMStreamSession {
private final static Log _log = new Log(SAMStreamSession.class);
private final static int SOCKET_HANDLER_BUF_SIZE = 32768;
protected final static int SOCKET_HANDLER_BUF_SIZE = 32768;
private SAMStreamReceiver recv = null;
protected SAMStreamReceiver recv = null;
private SAMStreamSessionServer server = null;
private I2PSocketManager socketMgr = null;
protected I2PSocketManager socketMgr = null;
private Object handlersMapLock = new Object();
/** stream id (Long) to SAMStreamSessionSocketReader */
@@ -65,13 +65,14 @@ public class SAMStreamSession {
private int lastNegativeId = 0;
// Can we create outgoing connections?
private boolean canCreate = false;
protected boolean canCreate = false;
/**
* should we flush every time we get a STREAM SEND, or leave that up to
* the streaming lib to decide?
*/
private boolean forceFlush = false;
protected boolean forceFlush = false;
public static String PROP_FORCE_FLUSH = "sam.forceFlush";
public static String DEFAULT_FORCE_FLUSH = "false";
@@ -189,7 +190,7 @@ public class SAMStreamSession {
* @throws InterruptedIOException if the connection timeouts
* @throws I2PException if there's another I2P-related error
*/
public boolean connect(int id, String dest, Properties props) throws I2PException, ConnectException, NoRouteToHostException, DataFormatException, InterruptedIOException, SAMInvalidDirectionException {
public boolean connect ( int id, String dest, Properties props ) throws I2PException, ConnectException, NoRouteToHostException, DataFormatException, InterruptedIOException, SAMInvalidDirectionException, IOException {
if (!canCreate) {
_log.debug("Trying to create an outgoing connection using a receive-only session");
throw new SAMInvalidDirectionException("Trying to create connections through a receive-only session");
@@ -208,10 +209,15 @@ public class SAMStreamSession {
opts.setConnectTimeout(60 * 1000);
_log.debug("Connecting new I2PSocket...");
// blocking connection (SAMv1)
I2PSocket i2ps = socketMgr.connect(d, opts);
createSocketHandler(i2ps, id);
recv.notifyStreamOutgoingConnection ( id, "OK", null );
return true;
}
@@ -277,7 +283,7 @@ public class SAMStreamSession {
*
* @return An id associated to the socket handler
*/
private int createSocketHandler(I2PSocket s, int id) {
protected int createSocketHandler ( I2PSocket s, int id ) {
SAMStreamSessionSocketReader reader = null;
StreamSender sender = null;
if (id == 0) {
@@ -285,8 +291,8 @@ public class SAMStreamSession {
}
try {
reader = new SAMStreamSessionSocketReader(s, id);
sender = new StreamSender(s, id);
reader = newSAMStreamSessionSocketReader(s, id);
sender = newStreamSender(s, id);
} catch (IOException e) {
_log.error("IOException when creating SAM STREAM session socket handler", e);
recv.stopStreamReceiving();
@@ -318,7 +324,7 @@ public class SAMStreamSession {
*
* @param id Handler id
*/
private SAMStreamSessionSocketReader getSocketReader(int id) {
protected SAMStreamSessionSocketReader getSocketReader ( int id ) {
synchronized (handlersMapLock) {
return (SAMStreamSessionSocketReader)handlersMap.get(new Integer(id));
}
@@ -334,7 +340,7 @@ public class SAMStreamSession {
*
* @param id Handler id
*/
private boolean checkSocketHandlerId(int id) {
protected boolean checkSocketHandlerId ( int id ) {
synchronized (handlersMapLock) {
return (!(handlersMap.get(new Integer(id)) == null));
}
@@ -345,7 +351,7 @@ public class SAMStreamSession {
*
* @param id Handler id to be removed
*/
private void removeSocketHandler(int id) {
protected void removeSocketHandler ( int id ) {
SAMStreamSessionSocketReader reader = null;
StreamSender sender = null;
@@ -446,7 +452,8 @@ public class SAMStreamSession {
}
_log.debug("New connection id: " + id);
recv.notifyStreamConnection(id, i2ps.getPeerDestination());
recv.notifyStreamIncomingConnection ( id, i2ps.getPeerDestination() );
} catch (I2PException e) {
_log.debug("Caught I2PException", e);
break;
@@ -469,29 +476,62 @@ public class SAMStreamSession {
}
boolean setReceiveLimit ( int id, long limit, boolean nolimit )
{
_log.debug ( "Protocol v1 does not support a receive limit for streams" );
return false ;
}
/**
* SAM STREAM socket handler, running in its own thread. It forwards
* SAM STREAM socket reader, running in its own thread. It forwards
* forward data to/from an I2P socket.
*
* @author human
*/
public class SAMStreamSessionSocketReader implements Runnable {
private I2PSocket i2pSocket = null;
protected I2PSocket i2pSocket = null;
private Object runningLock = new Object();
private boolean stillRunning = true;
protected Object runningLock = new Object();
protected boolean stillRunning = true;
protected int id;
private int id;
/**
* Create a new SAM STREAM session socket reader
*
* @param s Socket to be handled
* @param id Unique id assigned to the handler
*/
public SAMStreamSessionSocketReader(I2PSocket s, int id) throws IOException {
_log.debug("Instantiating new SAM STREAM session socket handler");
public SAMStreamSessionSocketReader ( I2PSocket s, int id ) throws IOException {}
/**
* Stop a SAM STREAM session socket reader thread immediately.
*/
public void stopRunning() {}
public void run() {}
}
protected SAMStreamSessionSocketReader
newSAMStreamSessionSocketReader ( I2PSocket s, int id ) throws IOException {
return new SAMv1StreamSessionSocketReader ( s, id );
}
public class SAMv1StreamSessionSocketReader extends SAMStreamSessionSocketReader {
/**
* Create a new SAM STREAM session socket reader
*
* @param s Socket to be handled
* @param id Unique id assigned to the handler
*/
public SAMv1StreamSessionSocketReader ( I2PSocket s, int id ) throws IOException {
super(s, id);
_log.debug("Instantiating new SAM STREAM session socket reader");
i2pSocket = s;
this.id = id;
@@ -507,6 +547,7 @@ public class SAMStreamSession {
if (stillRunning) {
stillRunning = false;
}
runningLock.notifyAll() ;
}
}
@@ -558,7 +599,40 @@ public class SAMStreamSession {
* Lets us push data through the stream without blocking, (even after exceeding
* the I2PSocket's buffer)
*/
private class StreamSender implements Runnable {
protected class StreamSender implements Runnable {
public StreamSender ( I2PSocket s, int id ) throws IOException {}
/**
* Send bytes through the SAM STREAM session socket sender
*
* @param data Data to be sent
*
* @throws IOException if the client didnt provide enough data
*/
public void sendBytes ( InputStream in, int size ) throws IOException {}
/**
* Stop a SAM STREAM session socket sender thread immediately
*
*/
public void stopRunning() {}
/**
* Stop a SAM STREAM session socket sender gracefully: stop the
* sender thread once all pending data has been sent.
*/
public void shutDownGracefully() {}
public void run() {}
}
protected StreamSender newStreamSender ( I2PSocket s, int id ) throws IOException {
return new v1StreamSender ( s, id ) ;
}
protected class v1StreamSender extends StreamSender
{
private List _data;
private int _id;
private ByteCache _cache;
@@ -567,7 +641,8 @@ public class SAMStreamSession {
private Object runningLock = new Object();
private I2PSocket i2pSocket = null;
public StreamSender(I2PSocket s, int id) throws IOException {
public v1StreamSender ( I2PSocket s, int id ) throws IOException {
super ( s, id );
_data = new ArrayList(1);
_id = id;
_cache = ByteCache.getInstance(4, 32*1024);

View File

@@ -35,6 +35,8 @@ import net.i2p.util.Log;
* @author human
*/
public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramReceiver, SAMStreamReceiver {
protected int verMajorId = 1;
protected int verMinorId = 0;
private final static Log _log = new Log(SAMv1Handler.class);
@@ -42,7 +44,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
private SAMRawSession rawSession = null;
private SAMDatagramSession datagramSession = null;
private SAMStreamSession streamSession = null;
protected SAMStreamSession streamSession = null;
private long _id;
private static volatile long __id = 0;
@@ -74,11 +76,15 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
_id = ++__id;
_log.debug("SAM version 1 handler instantiated");
if ((this.verMajor != 1) || (this.verMinor != 0)) {
if ( ! verifVersion() ) {
throw new SAMException("BUG! Wrong protocol version!");
}
}
public boolean verifVersion() {
return ( verMajor == 1 && verMinor == 0 ) ;
}
public void handle() {
String msg = null;
String domain = null;
@@ -248,7 +254,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
props.remove("DIRECTION");
streamSession = new SAMStreamSession(destKeystream, dir,props,this);
streamSession = newSAMStreamSession(destKeystream, dir,props);
} else {
_log.debug("Unrecognized SESSION STYLE: \"" + style +"\"");
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized SESSION STYLE\"\n");
@@ -275,6 +281,13 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
}
SAMStreamSession newSAMStreamSession(String destKeystream, String direction, Properties props )
throws IOException, DataFormatException, SAMException
{
return new SAMStreamSession(destKeystream, direction, props, this) ;
}
/* Parse and execute a DEST message*/
private boolean execDestMessage(String opcode, Properties props) {
@@ -489,7 +502,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
/* Parse and execute a STREAM message */
private boolean execStreamMessage(String opcode, Properties props) {
protected boolean execStreamMessage(String opcode, Properties props) {
if (streamSession == null) {
_log.error("STREAM message received, but no STREAM session exists");
return false;
@@ -508,7 +521,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
}
private boolean execStreamSend(Properties props) {
protected boolean execStreamSend(Properties props) {
if (props == null) {
_log.debug("No parameters specified in STREAM SEND message");
return false;
@@ -570,7 +583,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
}
private boolean execStreamConnect(Properties props) {
protected boolean execStreamConnect(Properties props) {
if (props == null) {
_log.debug("No parameters specified in STREAM CONNECT message");
return false;
@@ -604,39 +617,38 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
props.remove("DESTINATION");
try {
if (!streamSession.connect(id, dest, props)) {
_log.debug("STREAM connection failed");
return false;
try {
if (!streamSession.connect(id, dest, props)) {
_log.debug("STREAM connection failed");
return false;
}
} catch (DataFormatException e) {
_log.debug("Invalid destination in STREAM CONNECT message");
notifyStreamOutgoingConnection ( id, "INVALID_KEY", null );
} catch (SAMInvalidDirectionException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage());
notifyStreamOutgoingConnection ( id, "INVALID_DIRECTION", null );
} catch (ConnectException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage());
notifyStreamOutgoingConnection ( id, "CONNECTION_REFUSED", null );
} catch (NoRouteToHostException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage());
notifyStreamOutgoingConnection ( id, "CANT_REACH_PEER", null );
} catch (InterruptedIOException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage());
notifyStreamOutgoingConnection ( id, "TIMEOUT", null );
} catch (I2PException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage());
notifyStreamOutgoingConnection ( id, "I2P_ERROR", null );
}
return writeString("STREAM STATUS RESULT=OK ID=" + id + "\n");
} catch (DataFormatException e) {
_log.debug("Invalid destination in STREAM CONNECT message");
return writeString("STREAM STATUS RESULT=INVALID_KEY ID="
+ id + "\n");
} catch (SAMInvalidDirectionException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage());
return writeString("STREAM STATUS RESULT=INVALID_DIRECTION ID="
+ id + "\n");
} catch (ConnectException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage());
return writeString("STREAM STATUS RESULT=CONNECTION_REFUSED ID="
+ id + "\n");
} catch (NoRouteToHostException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage());
return writeString("STREAM STATUS RESULT=CANT_REACH_PEER ID="
+ id + "\n");
} catch (InterruptedIOException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage());
return writeString("STREAM STATUS RESULT=TIMEOUT ID="
+ id + "\n");
} catch (I2PException e) {
_log.debug("STREAM CONNECT failed: " + e.getMessage());
return writeString("STREAM STATUS RESULT=I2P_ERROR ID="
+ id + "\n");
} catch (IOException e) {
return false ;
}
return true ;
}
private boolean execStreamClose(Properties props) {
protected boolean execStreamClose(Properties props) {
if (props == null) {
_log.debug("No parameters specified in STREAM CLOSE message");
return false;
@@ -745,7 +757,41 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
// SAMStreamReceiver implementation
public void notifyStreamConnection(int id, Destination d) throws IOException {
public void streamSendAnswer( int id, String result, String bufferState ) throws IOException
{
if ( streamSession == null )
{
_log.error ( "BUG! Want to answer to stream SEND, but session is null!" );
throw new NullPointerException ( "BUG! STREAM session is null!" );
}
if ( !writeString ( "STREAM SEND ID=" + id
+ " RESULT=" + result
+ " STATE=" + bufferState
+ "\n" ) )
{
throw new IOException ( "Error notifying connection to SAM client" );
}
}
public void notifyStreamSendBufferFree( int id ) throws IOException
{
if ( streamSession == null )
{
_log.error ( "BUG! Stream outgoing buffer is free, but session is null!" );
throw new NullPointerException ( "BUG! STREAM session is null!" );
}
if ( !writeString ( "STREAM READY_TO_SEND ID=" + id + "\n" ) )
{
throw new IOException ( "Error notifying connection to SAM client" );
}
}
public void notifyStreamIncomingConnection(int id, Destination d) throws IOException {
if (streamSession == null) {
_log.error("BUG! Received stream connection, but session is null!");
throw new NullPointerException("BUG! STREAM session is null!");
@@ -758,6 +804,28 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
}
public void notifyStreamOutgoingConnection ( int id, String result, String msg ) throws IOException
{
if ( streamSession == null )
{
_log.error ( "BUG! Received stream connection, but session is null!" );
throw new NullPointerException ( "BUG! STREAM session is null!" );
}
String msgString = "" ;
if ( msg != null ) msgString = " MESSAGE=\"" + msg + "\"";
if ( !writeString ( "STREAM STATUS RESULT="
+ result
+ " ID=" + id
+ msgString
+ "\n" ) )
{
throw new IOException ( "Error notifying connection to SAM client" );
}
}
public void receiveStreamBytes(int id, byte data[], int len) throws IOException {
if (streamSession == null) {
_log.error("Received stream bytes, but session is null!");

View File

@@ -0,0 +1,196 @@
package net.i2p.sam;
/*
* free (adj.): unencumbered; not under the control of others
* Written by human in 2004 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.Socket;
import java.util.Properties;
import java.util.StringTokenizer;
import net.i2p.I2PException;
import net.i2p.client.I2PSessionException;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.util.Log;
/**
* Class able to handle a SAM version 2 client connection.
*
* @author mkvore
*/
public class SAMv2Handler extends SAMv1Handler implements SAMRawReceiver, SAMDatagramReceiver, SAMStreamReceiver
{
private final static Log _log = new Log ( SAMv2Handler.class );
/**
* Create a new SAM version 2 handler. This constructor expects
* that the SAM HELLO message has been still answered (and
* stripped) from the socket input stream.
*
* @param s Socket attached to a SAM client
* @param verMajor SAM major version to manage (should be 2)
* @param verMinor SAM minor version to manage
*/
public SAMv2Handler ( Socket s, int verMajor, int verMinor ) throws SAMException, IOException
{
this ( s, verMajor, verMinor, new Properties() );
}
/**
* Create a new SAM version 2 handler. This constructor expects
* that the SAM HELLO message has been still answered (and
* stripped) from the socket input stream.
*
* @param s Socket attached to a SAM client
* @param verMajor SAM major version to manage (should be 2)
* @param verMinor SAM minor version to manage
* @param i2cpProps properties to configure the I2CP connection (host, port, etc)
*/
public SAMv2Handler ( Socket s, int verMajor, int verMinor, Properties i2cpProps ) throws SAMException, IOException
{
super ( s, verMajor, verMinor, i2cpProps );
}
public boolean verifVersion()
{
return (verMajor == 2 && verMinor == 0) ;
}
SAMStreamSession newSAMStreamSession(String destKeystream, String direction, Properties props )
throws IOException, DataFormatException, SAMException
{
return new SAMv2StreamSession(destKeystream, direction, props, this) ;
}
/* Parse and execute a STREAM message */
protected boolean execStreamMessage ( String opcode, Properties props )
{
if ( streamSession == null )
{
_log.error ( "STREAM message received, but no STREAM session exists" );
return false;
}
if ( opcode.equals ( "SEND" ) )
{
return execStreamSend ( props );
}
else if ( opcode.equals ( "CONNECT" ) )
{
return execStreamConnect ( props );
}
else if ( opcode.equals ( "CLOSE" ) )
{
return execStreamClose ( props );
}
else if ( opcode.equals ( "RECEIVE") )
{
return execStreamReceive( props );
}
else
{
_log.debug ( "Unrecognized RAW message opcode: \""
+ opcode + "\"" );
return false;
}
}
private boolean execStreamReceive ( Properties props )
{
if ( props == null )
{
_log.debug ( "No parameters specified in STREAM RECEIVE message" );
return false;
}
int id;
{
String strid = props.getProperty ( "ID" );
if ( strid == null )
{
_log.debug ( "ID not specified in STREAM RECEIVE message" );
return false;
}
try
{
id = Integer.parseInt ( strid );
}
catch ( NumberFormatException e )
{
_log.debug ( "Invalid STREAM RECEIVE ID specified: " + strid );
return false;
}
}
boolean nolimit = false;
long limit = 0;
{
String strsize = props.getProperty ( "LIMIT" );
if ( strsize == null )
{
_log.debug ( "Limit not specified in STREAM RECEIVE message" );
return false;
}
if ( strsize.equals( "NONE" ) )
{
nolimit = true ;
}
else
{
try
{
limit = Long.parseLong ( strsize );
}
catch ( NumberFormatException e )
{
_log.debug ( "Invalid STREAM RECEIVE size specified: " + strsize );
return false;
}
if ( limit < 0 )
{
_log.debug ( "Specified limit (" + limit
+ ") is out of protocol limits" );
return false;
}
}
}
streamSession.setReceiveLimit ( id, limit, nolimit ) ;
return true;
}
}

View File

@@ -0,0 +1,574 @@
package net.i2p.sam;
/*
* free (adj.): unencumbered; not under the control of others
* Written by human in 2004 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import net.i2p.I2PException;
import net.i2p.client.I2PClient;
import net.i2p.client.streaming.I2PServerSocket;
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.data.Base64;
import net.i2p.data.ByteArray;
import net.i2p.data.DataHelper;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.util.ByteCache;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
/**
* SAMv2 STREAM session class.
*
* @author mkvore
*/
public class SAMv2StreamSession extends SAMStreamSession
{
private final static Log _log = new Log ( SAMv2StreamSession.class );
/**
* Create a new SAM STREAM session.
*
* @param dest Base64-encoded destination (private key)
* @param dir Session direction ("RECEIVE", "CREATE" or "BOTH")
* @param props Properties to setup the I2P session
* @param recv Object that will receive incoming data
*/
public SAMv2StreamSession ( String dest, String dir, Properties props,
SAMStreamReceiver recv ) throws IOException, DataFormatException, SAMException
{
super ( dest, dir, props, recv );
}
/**
* Create a new SAM STREAM session.
*
* @param destStream Input stream containing the destination keys
* @param dir Session direction ("RECEIVE", "CREATE" or "BOTH")
* @param props Properties to setup the I2P session
* @param recv Object that will receive incoming data
*/
public SAMv2StreamSession ( InputStream destStream, String dir,
Properties props, SAMStreamReceiver recv ) throws IOException, DataFormatException, SAMException
{
super ( destStream, dir, props, recv );
}
/**
* Connect the SAM STREAM session to the specified Destination
*
* @param id Unique id for the connection
* @param dest Base64-encoded Destination to connect to
* @param props Options to be used for connection
*
* @throws DataFormatException if the destination is not valid
* @throws SAMInvalidDirectionException if trying to connect through a
* receive-only session
* @return true if the communication with the SAM client is ok
*/
public boolean connect ( int id, String dest, Properties props )
throws DataFormatException, SAMInvalidDirectionException
{
if ( !canCreate )
{
_log.debug ( "Trying to create an outgoing connection using a receive-only session" );
throw new SAMInvalidDirectionException ( "Trying to create connections through a receive-only session" );
}
if ( checkSocketHandlerId ( id ) )
{
_log.debug ( "The specified id (" + id + ") is already in use" );
return false ;
}
Destination d = new Destination();
d.fromBase64 ( dest );
I2PSocketOptions opts = socketMgr.buildOptions ( props );
if ( props.getProperty ( I2PSocketOptions.PROP_CONNECT_TIMEOUT ) == null )
opts.setConnectTimeout ( 60 * 1000 );
_log.debug ( "Connecting new I2PSocket..." );
// non-blocking connection (SAMv2)
StreamConnector connector ;
connector = new StreamConnector ( id, d, opts );
I2PThread connectThread = new I2PThread ( connector, "StreamConnector" + id ) ;
connectThread.start() ;
return true ;
}
/**
* SAM STREAM socket connecter, running in its own thread.
*
* @author mkvore
*/
public class StreamConnector implements Runnable
{
private Object runningLock = new Object();
private boolean stillRunning = true;
private int id;
private Destination dest ;
private I2PSocketOptions opts ;
/**
* Create a new SAM STREAM session socket reader
*
* @param id Unique id assigned to the handler
* @param dest Destination to reach
* @param opts Socket options (I2PSocketOptions)
*/
public StreamConnector ( int id, Destination dest, I2PSocketOptions opts )// throws IOException
{
_log.debug ( "Instantiating new SAM STREAM connector" );
this.id = id ;
this.opts = opts ;
this.dest = dest ;
}
public void run()
{
_log.debug ( "run() called for socket connector " + id );
try
{
try
{
I2PSocket i2ps = socketMgr.connect ( dest, opts );
createSocketHandler ( i2ps, id );
recv.notifyStreamOutgoingConnection ( id, "OK", null );
}
catch ( DataFormatException e )
{
_log.debug ( "Invalid destination in STREAM CONNECT message" );
recv.notifyStreamOutgoingConnection ( id, "INVALID_KEY", e.getMessage() );
}
catch ( ConnectException e )
{
_log.debug ( "STREAM CONNECT failed: " + e.getMessage() );
recv.notifyStreamOutgoingConnection ( id, "CONNECTION_REFUSED", e.getMessage() );
}
catch ( NoRouteToHostException e )
{
_log.debug ( "STREAM CONNECT failed: " + e.getMessage() );
recv.notifyStreamOutgoingConnection ( id, "CANT_REACH_PEER", e.getMessage() );
}
catch ( InterruptedIOException e )
{
_log.debug ( "STREAM CONNECT failed: " + e.getMessage() );
recv.notifyStreamOutgoingConnection ( id, "TIMEOUT", e.getMessage() );
}
catch ( I2PException e )
{
_log.debug ( "STREAM CONNECT failed: " + e.getMessage() );
recv.notifyStreamOutgoingConnection ( id, "I2P_ERROR", e.getMessage() );
}
}
catch ( IOException e )
{
_log.debug ( "Error sending disconnection notice for handler "
+ id, e );
}
_log.debug ( "Shutting down SAM STREAM session connector " + id );
}
}
/**
* Lets us push data through the stream without blocking, (even after exceeding
* the I2PSocket's buffer)
*/
protected StreamSender newStreamSender ( I2PSocket s, int id ) throws IOException
{
return new v2StreamSender ( s, id ) ;
}
protected SAMStreamSessionSocketReader
newSAMStreamSessionSocketReader(I2PSocket s, int id ) throws IOException
{
return new SAMv2StreamSessionSocketReader(s,id);
}
protected class v2StreamSender extends StreamSender
{
private List _data;
private int _dataSize;
private int _id;
private ByteCache _cache;
private OutputStream _out = null;
private boolean _stillRunning, _shuttingDownGracefully;
private Object runningLock = new Object();
private I2PSocket i2pSocket = null;
public v2StreamSender ( I2PSocket s, int id ) throws IOException
{
super ( s, id );
_data = new ArrayList ( 1 );
_dataSize = 0;
_id = id;
_cache = ByteCache.getInstance ( 10, 32 * 1024 );
_out = s.getOutputStream();
_stillRunning = true;
_shuttingDownGracefully = false;
i2pSocket = s;
}
/**
* Send bytes through the SAM STREAM session socket sender
*
* @param data Data to be sent
*
* @throws IOException if the client didnt provide enough data
*/
public void sendBytes ( InputStream in, int size ) throws IOException
{
if ( _log.shouldLog ( Log.DEBUG ) )
_log.debug ( "Handler " + _id + ": sending " + size + " bytes" );
ByteArray ba = _cache.acquire();
int read = DataHelper.read ( in, ba.getData(), 0, size );
if ( read != size )
throw new IOException ( "Insufficient data from the SAM client (" + read + "/" + size + ")" );
ba.setValid ( read );
synchronized ( _data )
{
if ( _dataSize >= SOCKET_HANDLER_BUF_SIZE )
{
_cache.release ( ba, false );
recv.streamSendAnswer ( _id, "FAILED", "BUFFER_FULL" ) ;
}
else
{
_dataSize += size ;
_data.add ( ba );
_data.notifyAll();
if ( _dataSize >= SOCKET_HANDLER_BUF_SIZE )
{
recv.streamSendAnswer ( _id, "OK", "BUFFER_FULL" ) ;
}
else
{
recv.streamSendAnswer ( _id, "OK", "READY" );
}
}
}
}
/**
* Stop a SAM STREAM session socket sender thread immediately
*
*/
public void stopRunning()
{
_log.debug ( "stopRunning() invoked on socket sender " + _id );
synchronized ( runningLock )
{
if ( _stillRunning )
{
_stillRunning = false;
try
{
i2pSocket.close();
}
catch ( IOException e )
{
_log.debug ( "Caught IOException", e );
}
synchronized ( _data )
{
_data.clear();
_data.notifyAll();
}
}
}
}
/**
* Stop a SAM STREAM session socket sender gracefully: stop the
* sender thread once all pending data has been sent.
*/
public void shutDownGracefully()
{
_log.debug ( "shutDownGracefully() invoked on socket sender " + _id );
_shuttingDownGracefully = true;
}
public void run()
{
_log.debug ( "run() called for socket sender " + _id );
ByteArray data = null;
while ( _stillRunning )
{
data = null;
try
{
synchronized ( _data )
{
if ( _data.size() > 0 )
{
int formerSize = _dataSize ;
data = ( ByteArray ) _data.remove ( 0 );
_dataSize -= data.getValid();
if ( ( formerSize >= SOCKET_HANDLER_BUF_SIZE ) && ( _dataSize < SOCKET_HANDLER_BUF_SIZE ) )
recv.notifyStreamSendBufferFree ( _id );
}
else if ( _shuttingDownGracefully )
{
/* No data left and shutting down gracefully?
If so, stop the sender. */
stopRunning();
break;
}
else
{
/* Wait for data. */
_data.wait ( 5000 );
}
}
if ( data != null )
{
try
{
_out.write ( data.getData(), 0, data.getValid() );
if ( forceFlush )
{
// i dont like doing this, but it clears the buffer issues
_out.flush();
}
}
catch ( IOException ioe )
{
// ok, the stream failed, but the SAM client didn't
if ( _log.shouldLog ( Log.WARN ) )
_log.warn ( "Stream failed", ioe );
removeSocketHandler ( _id );
stopRunning();
}
finally
{
_cache.release ( data, false );
}
}
}
catch ( InterruptedException ie ) {}
catch ( IOException e ) {}}
synchronized ( _data )
{
_data.clear();
}
}
}
/**
* Send bytes through a SAM STREAM session.
*
* @param data Bytes to be sent
*
* @return True if the data was queued for sending, false otherwise
*/
public boolean setReceiveLimit ( int id, long limit, boolean nolimit )
{
SAMStreamSessionSocketReader reader = getSocketReader ( id );
if ( reader == null )
{
if ( _log.shouldLog ( Log.WARN ) )
_log.warn ( "Trying to set a limit to a nonexistent reader " + id );
return false;
}
( (SAMv2StreamSessionSocketReader) reader).setLimit ( limit, nolimit );
return true;
}
/**
* SAM STREAM socket reader, running in its own thread. It forwards
* forward data to/from an I2P socket.
*
* @author human
*/
public class SAMv2StreamSessionSocketReader extends SAMv1StreamSessionSocketReader
{
protected boolean nolimit ;
protected long limit ;
protected long totalReceived ;
/**
* Create a new SAM STREAM session socket reader
*
* @param s Socket to be handled
* @param id Unique id assigned to the handler
*/
public SAMv2StreamSessionSocketReader ( I2PSocket s, int id ) throws IOException
{
super ( s, id );
nolimit = false ;
limit = 0 ;
totalReceived = 0 ;
}
public void setLimit ( long limit, boolean nolimit )
{
synchronized (runningLock)
{
this.limit = limit ;
this.nolimit = nolimit ;
runningLock.notify() ;
}
_log.debug ( "new limit set for socket reader " + id + " : " + (nolimit ? "NOLIMIT" : limit + " bytes" ) );
}
public void run()
{
_log.debug ( "run() called for socket reader " + id );
int read = -1;
byte[] data = new byte[SOCKET_HANDLER_BUF_SIZE];
try
{
InputStream in = i2pSocket.getInputStream();
while ( stillRunning )
{
synchronized (runningLock)
{
while ( stillRunning && ( !nolimit && totalReceived >= limit) )
{
try{
runningLock.wait() ;
}
catch (InterruptedException ie)
{}
}
if ( !stillRunning )
break ;
}
read = in.read ( data );
if ( read == -1 )
{
_log.debug ( "Handler " + id + ": connection closed" );
break;
}
totalReceived += read ;
recv.receiveStreamBytes ( id, data, read );
}
}
catch ( IOException e )
{
_log.debug ( "Caught IOException", e );
}
try
{
i2pSocket.close();
}
catch ( IOException e )
{
_log.debug ( "Caught IOException", e );
}
if ( stillRunning )
{
removeSocketHandler ( id );
// FIXME: we need error reporting here!
try
{
recv.notifyStreamDisconnection ( id, "OK", null );
}
catch ( IOException e )
{
_log.debug ( "Error sending disconnection notice for handler "
+ id, e );
}
}
_log.debug ( "Shutting down SAM STREAM session socket handler " + id );
}
}
}

View File

@@ -302,24 +302,35 @@ public class ConnectionPacketHandler {
_context.statManager().addRateData("stream.trend", trend, newWindowSize);
if ( (!congested) && (acked > 0) && (numResends <= 0) ) {
if (trend < 0) {
if (newWindowSize < con.getLastCongestionSeenAt() / 2) {
// Don't make this <= LastCongestion/2 or we'll jump right back to where we were
// slow start - exponential growth
// grow acked/N times (where N = the slow start factor)
// always grow at least 1
int factor = con.getOptions().getSlowStartGrowthRateFactor();
if (factor <= 1)
newWindowSize += acked;
else if (acked < factor)
newWindowSize++;
else
newWindowSize += acked / factor;
if (_log.shouldLog(Log.DEBUG))
_log.debug("slow start acks = " + acked + " for " + con);
} else if (trend < 0) {
// rtt is shrinking, so lets increment the cwin
newWindowSize++;
} else if (newWindowSize > con.getLastCongestionSeenAt() / 2) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("trend < 0 for " + con);
} else {
// congestion avoidance
// we can't use newWindowSize += 1/newWindowSize, since we're
// linear growth - increase window 1/N per RTT
// we can't use newWindowSize += acked/(oldWindow*N) (where N = the cong. avoid. factor), since we're
// integers, so lets use a random distribution instead
int shouldIncrement = _context.random().nextInt(con.getOptions().getCongestionAvoidanceGrowthRateFactor()*newWindowSize);
if (shouldIncrement <= 0)
newWindowSize += 1;
} else {
// slow start, but modified to take into account the fact
// that windows in the streaming lib are messages, not bytes,
// so we only grow 1 every N times (where N = the slow start factor)
int shouldIncrement = _context.random().nextInt(con.getOptions().getSlowStartGrowthRateFactor());
if (shouldIncrement <= 0)
if (shouldIncrement < acked)
newWindowSize += 1;
if (_log.shouldLog(Log.DEBUG))
_log.debug("cong. avoid acks = " + acked + " for " + con);
}
}

View File

@@ -129,7 +129,7 @@ public class I2PSocketManagerFull implements I2PSocketManager {
public long getAcceptTimeout() { return _acceptTimeout; }
public void setDefaultOptions(I2PSocketOptions options) {
_defaultOptions = new ConnectionOptions(options);
_defaultOptions = new ConnectionOptions((ConnectionOptions) options);
}
public I2PSocketOptions getDefaultOptions() {

View File

@@ -19,7 +19,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Revision: 1.1 $
* $Revision: 1.2 $
*/
package i2p.susi.dns;
@@ -76,6 +76,8 @@ public class AddressbookBean
deletionMarks = new LinkedList();
}
private long configLastLoaded = 0;
private static final String PRIVATE_BOOK = "private_addressbook";
private static final String DEFAULT_PRIVATE_BOOK = "../privatehosts.txt";
private void loadConfig()
{
long currentTime = System.currentTimeMillis();
@@ -86,6 +88,9 @@ public class AddressbookBean
try {
properties.clear();
properties.load( new FileInputStream( ConfigBean.configFileName ) );
// added in 0.5, for compatibility with 0.4 config.txt
if( properties.getProperty(PRIVATE_BOOK) == null)
properties.setProperty(PRIVATE_BOOK, DEFAULT_PRIVATE_BOOK);
configLastLoaded = currentTime;
}
catch (Exception e) {
@@ -112,8 +117,9 @@ public class AddressbookBean
public String getBook()
{
if( book == null || ( book.compareToIgnoreCase( "master" ) != 0 &&
book.compareToIgnoreCase( "router" ) != 0 ) &&
book.compareToIgnoreCase( "published" ) != 0 )
book.compareToIgnoreCase( "router" ) != 0 &&
book.compareToIgnoreCase( "private" ) != 0 &&
book.compareToIgnoreCase( "published" ) != 0 ))
book = "master";
return book;
@@ -163,7 +169,11 @@ public class AddressbookBean
list.addLast( new AddressBean( name, destination ) );
}
// Format a message about filtered addressbook size, and the number of displayed entries
message = "Filtered list contains " + list.size() + " entries";
if( filter != null && filter.length() > 0 )
message = "Filtered l";
else
message = "L";
message += "ist contains " + list.size() + " entries";
if (list.size() > 300) message += ", displaying the first 300."; else message += ".";
Object array[] = list.toArray();
@@ -251,6 +261,10 @@ public class AddressbookBean
{
return getBook().compareToIgnoreCase( "published" ) == 0;
}
public boolean isPrivate()
{
return getBook().compareToIgnoreCase( "private" ) == 0;
}
public void setFilter(String filter) {
if( filter != null && ( filter.length() == 0 || filter.compareToIgnoreCase( "none" ) == 0 ) ) {
filter = null;

View File

@@ -19,14 +19,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Revision: 1.4 $
* $Revision: 1.1 $
*/
package i2p.susi.dns;
public class VersionBean {
private static String version = "0.4";
private static String version = "0.5";
private static String url = "http://susi.i2p/?i2paddresshelper=T2DU1KAz3meB0B53U8Y06-I7vHR7XmC0qXAJfLW6b-1L1FVKoySRZz4xazHAwyv2xtRpvKrv6ukLm1tThEW0zQWtZPtX8G6KkzMibD8t7IS~4yw-9VkBtUydyYfsX08AK3v~-egSW8HCXTdyIJVtrETJb337VDUHW-7D4L1JLbwSH4if2ooks6yFTrljK5aVMi-16dZOVvmoyJc3jBqSdK6kraO4gW5-vHTmbLwL498p9nug1KOg1DqgN2GeU5X1QlVrlpFb~IIfdP~O8NT7u-LAjW3jSJsMbLDHMSYTIhC7xmJIiBoi-qk8p6TLynAmvJ7HRvbx4N1EB-uJHyD16wsZkkHyEOfmXbj0ZqLyKEGb3thPwCz-M9v~c2Qt3WbwjXJAtHpjlHkdJ4Fg91cX2oak~JoapnPf6Syw8hko5syf6VVoCYLnrrYyM8oGl8mLclHkj~VCidQNqMSM74IhrHfK6HmRikqtZBexb5M6wfMTTqBvaHURdD21GOpFKYBUAAAA";
public String getVersion() {

View File

@@ -20,7 +20,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Revision: 1.2 $
* $Revision: 1.3 $
*/
%>
<%@ page contentType="text/html"%>
@@ -48,9 +48,11 @@
<p>addressbooks
<a href="addressbook.jsp?book=master">master</a> |
<a href="addressbook.jsp?book=router">router</a> |
<a href="addressbook.jsp?book=published">published</a> *
<a href="addressbook.jsp?book=published">published</a> |
<a href="addressbook.jsp?book=private">private</a> *
<a href="subscriptions.jsp">subscriptions</a> *
<a href="config.jsp">configuration</a>
<a href="config.jsp">configuration</a> *
<a href="index.jsp">overview</a>
</p>
</div>
@@ -92,7 +94,8 @@
<a href="addressbook.jsp?filter=0-9">0-9</a>
<a href="addressbook.jsp?filter=none">all</a></p>
<c:if test="${book.hasFilter}">
<p>Current filter: ${book.filter}</p>
<p>Current filter: ${book.filter}
(<a href="addressbook.jsp?filter=none">clear filter</a>)</p>
</c:if>
</div>
@@ -117,7 +120,7 @@
<table class="book" cellspacing="0" cellpadding="5">
<tr class="head">
<c:if test="${book.master || book.router || book.published}">
<c:if test="${book.master || book.router || book.published || book.private}">
<th>&nbsp;</th>
</c:if>
@@ -127,7 +130,7 @@
<!-- limit iterator to 300, or "Form too large" may result on submit -->
<c:forEach items="${book.entries}" var="addr" begin="0" end="299">
<tr class="list${book.trClass}">
<c:if test="${book.master || book.router || book.published}">
<c:if test="${book.master || book.router || book.published || book.private}">
<td class="checkbox"><input type="checkbox" name="checked" value="${addr.name}" alt="Mark for deletion"></td>
</c:if>
<td class="names"><a href="http://${addr.name}/">${addr.name}</a> -
@@ -139,7 +142,7 @@
</table>
</div>
<c:if test="${book.master || book.router || book.published}">
<c:if test="${book.master || book.router || book.published || book.private}">
<div id="buttons">
<p class="buttons"><input type="image" name="action" value="delete" src="images/delete.png" alt="Delete checked" />
</p>

View File

@@ -20,7 +20,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Revision: 1.14 $
* $Revision: 1.1 $
*/
%>
<%@ page contentType="text/html" %>
@@ -43,9 +43,11 @@
addressbooks
<a href="addressbook.jsp?book=master">master</a> |
<a href="addressbook.jsp?book=router">router</a> |
<a href="addressbook.jsp?book=published">published</a> *
<a href="addressbook.jsp?book=published">published</a> |
<a href="addressbook.jsp?book=private">private</a> *
<a href="subscriptions.jsp">subscriptions</a> *
<a href="config.jsp">configuration</a>
configuration *
<a href="index.jsp">overview</a>
</p>
</div>
<div id="headline">
@@ -65,22 +67,22 @@ addressbooks
<div id="help">
<h3>Hints</h3>
<ol>
<li>All file or directory paths here are relative to the addressbooks working directory, which normally
<li>All file or directory paths here are relative to the addressbook's working directory, which normally
is located at $I2P/addressbook/.</li>
<li>If you want to manually add lines to an addressbook, add them to the master addressbook. The router
<li>If you want to manually add lines to an addressbook, add them to the private or master addressbooks. The router
addressbook and the published addressbook are overwritten by the addressbook application.</li>
<li><b>Important:</b>When you publish your addressbook, <b>ALL</b> destinations appear there, even those
from your master addressbook. Unfortunately the master addressbook points to your userhosts.txt, which was
used for private destinations before. So if you want to keep the destinations in your userhosts.txt secret,
please change the master addressbook to a different file before turning on addressbook publishing.</li>
<li><b>Important:</b>When you publish your addressbook, <b>ALL</b> destinations from the master and router addressbooks appear there.
Use the private addressbook for private destinations, these are not published.
</li>
</ol>
<h3>Options</h3>
<ul>
<li><b>subscriptions</b> - file containing the list of subscriptions URLs (no need to change)</li>
<li><b>update_delay</b> - update interval in hours (no need to change)</li>
<li><b>published_addressbook</b> - your public hosts.txt file (choose a path within your webserver document root)</li>
<li><b>router_addressbook</b> - your hosts.txt (no need to change)</li>
<li><b>master_addressbook</b> - your personal addressbook, it gets never overwritten by the addressbook</li>
<li><b>router_addressbook</b> - your hosts.txt (don't change)</li>
<li><b>master_addressbook</b> - your personal addressbook, it never gets overwritten by the addressbook (don't change)</li>
<li><b>private_addressbook</b> - your private addressbook, it is never published (defaults to ../privatehosts.txt, don't change)</li>
<li><b>proxy_port</b> - http port for your eepProxy (no need to change)</li>
<li><b>proxy_host</b> - hostname for your eepProxy (no need to change)</li>
<li><b>should_publish</b> - true/false whether to write the published addressbook</li>
@@ -93,4 +95,4 @@ please change the master addressbook to a different file before turning on addre
<p class="footer">susidns v${version.version} &copy; <a href="${version.url}">susi</a> 2005 </p>
</div>
</body>
</html>
</html>

View File

@@ -20,7 +20,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Revision: 1.1 $
* $Revision: 1.2 $
*/
%>
<%@ page contentType="text/html"%>
@@ -42,9 +42,11 @@
<p>addressbooks
<a href="addressbook.jsp?book=master">master</a> |
<a href="addressbook.jsp?book=router">router</a> |
<a href="addressbook.jsp?book=published">published</a> *
<a href="addressbook.jsp?book=published">published</a> |
<a href="addressbook.jsp?book=private">private</a> *
<a href="subscriptions.jsp">subscriptions</a> *
<a href="config.jsp">configuration</a>
<a href="config.jsp">configuration</a> *
overview
</p>
</div>
@@ -52,23 +54,25 @@
<h3>Huh? what addressbook?</h3>
<p>
The addressbook application is part of your i2p installation. It regularly updates your hosts.txt file
from distributed sources. It keeps your hosts.txt up to date, so it automatically contains all new
eepsites announced on <a href="http://orion.i2p">orion</a>
or in the <a href="http://forum.i2p/viewforum.php?f=16">forum</a>.
from distributed sources. It keeps your hosts.txt up to date, so it can automatically add
eepsites announced on other sites if you subscribe to those sites' addressbooks.
</p>
<p>
(To speak the truth: In its default configuration the addressbook does not poll
orion, but dev.i2p only. Subscribing to <a href="http://orion.i2p">orion</a> is an easy task,
just add <a href="http://orion.i2p/hosts.txt">http://orion.i2p/hosts.txt</a> to your <a href="subscriptions.jsp">subscriptions</a> file.)
additional sites, but www.i2p2.i2p only. Subscribing to additional sites is an easy task,
just add them to your <a href="subscriptions.jsp">subscriptions</a> file.)
</p>
<p>If you have questions about naming in i2p, there is an excellent <a href="http://forum.i2p.net/viewtopic.php?t=134">introduction</a>
from duck in the forum.</p>
<p>If you have questions about naming in i2p, there is an excellent <a href="http://forum.i2p/viewtopic.php?t=134">introduction</a>
from duck in the forum and <a href="http://www.i2p2.i2p/naming.html">additional information on www.i2p2.i2p</a>.</p>
<h3>How does the addressbook work?</h3>
<p>The addressbook application regularly (normally once per hour) polls your subscriptions and merges their content
into your so called router addressbook (normally your plain hosts.txt). Then it merges your so called master addressbook (normally
your userhosts.txt) into the router addressbook as well. If configured the router addressbook is now written to the so published addressbook,
which is a publicly available copy of your hosts.txt somewhere in your eepsites document root. (Yes, this means that, with activated publication,
your once private keys from userhosts.txt now are publicly available for everybody.)
into your so-called router addressbook (normally your plain hosts.txt). Then it merges your so-called master addressbook (normally
your userhosts.txt) into the router addressbook as well. If configured, the router addressbook is now written to the published addressbook,
which is a publicly available copy of your hosts.txt somewhere in your eepsite's document root.
</p><p>
The router also uses a private addressbook (privatehosts.txt, not shown in the picture), which is not merged or published.
Hosts in the private addressbook can be accessed by you but their addresses are never distributed to others.
The private addressbook can also be used for aliases of hosts in your other addressbooks.
</p>
<p><img src="images/how.png" border="0" alt="addressbook working scheme"/></p>
</div>

View File

@@ -20,7 +20,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Revision: 1.7 $
* $Revision: 1.2 $
*/
%>
<%@ page contentType="text/html"%>
@@ -42,9 +42,11 @@
<p>addressbooks
<a href="addressbook.jsp?book=master">master</a> |
<a href="addressbook.jsp?book=router">router</a> |
<a href="addressbook.jsp?book=published">published</a> *
<a href="subscriptions.jsp">subscriptions</a> *
<a href="config.jsp">configuration</a>
<a href="addressbook.jsp?book=published">published</a> |
<a href="addressbook.jsp?book=private">private</a> *
subscriptions *
<a href="config.jsp">configuration</a> *
<a href="index.jsp">overview</a>
</p>
</div>
<div id="headline">
@@ -66,9 +68,8 @@
<p class="help">
The subscription file contains a list of (i2p) URLs. The addressbook application
regularly (once per hour) checks this list for new eepsites. Those URLs simply contain the published hosts.txt
file of other people. Default subscription is the hosts.txt from dev.i2p. The most
popular collaboration site for eepsite is orion.i2p. So its a good idea to add http://orion.i2p/hosts.txt
as a 2nd subscription.
file of other people. The default subscription is the hosts.txt from www.i2p2.i2p, which is updated infrequently.
So it is a good idea to add additional subscriptions to sites that have the latest addresses.
</p>
</div>
<div id="footer">

View File

@@ -1578,7 +1578,7 @@ public class WebMail extends HttpServlet
"<tr><td>Host</td><td><input type=\"text\" size=\"32\" name=\"" + HOST +"\" value=\"" + host + "\"" + ( fixed ? " disabled" : "" ) + "></td></tr>\n" +
"<tr><td>POP3-Port</td><td><input type=\"text\" size=\"32\" name=\"" + POP3 +"\" value=\"" + pop3 + "\"" + ( fixed ? " disabled" : "" ) + "></td></tr>\n" +
"<tr><td>SMTP-Port</td><td><input type=\"text\" size=\"32\" name=\"" + SMTP +"\" value=\"" + smtp + "\"" + ( fixed ? " disabled" : "" ) + "></td></tr>\n" +
"<tr><td align=\"center\" colspan=\"2\">" + button( LOGIN, "Login" ) + " <input type=\"reset\" value=\"Reset\"></td></tr>\n" +
"<tr><td align=\"center\" colspan=\"2\"><a href=\"http://hq.postman.i2p/?page_id=16\">Create Account</a> " + button( LOGIN, "Login" ) + " <input type=\"reset\" value=\"Reset\"></td></tr>\n" +
"</table>");
}
/**

View File

@@ -3,7 +3,8 @@
<target name="all" >
<echo message="Useful targets: " />
<echo message=" dist: distclean then package everything up (installer, clean tarball, update tarball)" />
<echo message=" pkg: distclean then package everything up (installer, clean tarball, update tarball)" />
<echo message=" dist: pkg and javadoc" />
<echo message=" installer: build the GUI installer" />
<echo message=" tarball: tar the full install into i2p.tar.bz2 (extracts to build a new clean install)" />
<echo message=" updater: tar the built i2p specific files into an i2pupdate.zip (extracts safely over existing installs)" />
@@ -42,7 +43,7 @@
<copy file="router/java/build/router.jar" todir="build/" />
</target>
<target name="buildWEB">
<ant dir="apps/jetty" target="fetchJettylib" />
<ant dir="apps/jetty" target="ensureJettylib" />
<ant dir="apps/routerconsole/java" target="build" />
<copy file="apps/routerconsole/java/build/routerconsole.jar" todir="build/" />
<copy file="apps/routerconsole/java/build/routerconsole.war" todir="build/" />
@@ -138,6 +139,9 @@
<pathelement location="apps/i2ptunnel/java/src" />
<pathelement location="apps/systray/java/src" />
<pathelement location="apps/routerconsole/java/src" />
<pathelement location="apps/addressbook/java/src" />
<pathelement location="apps/i2psnark/java/src" />
<pathelement location="apps/sam/java/src" />
</sourcepath>
<classpath>
<pathelement location="apps/jetty/jettylib/org.mortbay.jetty.jar" />

71
checklist.txt Normal file
View File

@@ -0,0 +1,71 @@
Release checklist
-----------------
Sync with mtn.i2p2.i2p
Start with a clean checkout mtn -d i2p.mtn co --branch=i2p.i2p
Double-check trust list
Deploy the Jetty archive, a clean checkout lacks it
Change revision in:
history.txt
initialNews.xml
installer/install.xml
news.xml
router/java/src/net/i2p/router/RouterVersion.java
core/java/src/net/i2p/CoreVersion.java
Review the complete diff from the last release:
mtn diff -r t:i2p-0.6.1.(xx-1) > out.diff
vi out.diff
Build and tag:
ant pkg
mtn ci
mtn tag h: i2p-0.6.1.xx
Sync with mtn.i2p2.i2p
Create a signed update file with:
export I2P=~/i2p
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate sign i2pupdate.zip i2pupdate.sud /path/to/private.key 0.6.1.xx
Verify signed update file with:
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate showversion i2pupdate.sud
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate verifysig i2pupdate.sud
Make the source tarball:
Start with a clean checkout mtn -d i2p.mtn co --branch=i2p.i2p i2p-0.6.1.xx
Double-check trust list
tar cjf i2psource-0.6.1.xx.tar.bz2 --exclude i2p-0.6.1.xx/_MTN i2p-0.6.1.xx
mv i2p-0.6.1.xx.tar.bz2 i2p.i2p
Until the build script gets this ability, you need to rename some files:
mv i2pinstall.exe i2pinstall-0.6.1.xx.exe
mv i2p.tar.bz2 i2pheadless-0.6.1.xx.tar.bz2
mv i2pupdate.zip i2pupdate-0.6.1.xx.zip
you probably don't need to rename i2pupdate.sud
Generate hashes:
sha1sum i2p*0.6.1.xx.*
sha1sum i2pupdate.sud
now GPG-sign an announcement with the hashes
Generate PGP signatures:
gpg -b i2pinstall-0.6.1.xx.exe
gpg -b i2pheadless-0.6.1.xx.tar.bz2
gpg -b i2psource-0.6.1.xx.tar.bz2
gpg -b i2pupdate-0.6.1.xx.zip
gpg -b i2pupdate.sud
Distribute files to download locations and to www.i2p2.i2p
Website files to change:
Sync with mtn.i2p2.i2p
announcements.html
download.html (change SHA1s)
index.html
hosts.txt (copy from mtn)
Sync with mtn.i2p2.i2p
Copy news.xml to subscription location
Announce on #i2p, forum.i2p, Syndie

View File

@@ -1,9 +1,27 @@
Prior to building the jbigi library, you will need to fetch the GMP source
from http://www.swox.com/gmp/, saving it to jbigi/gmp-4.1.4.tar.bz2 (it will
from http://www.swox.com/gmp/, saving it to jbigi/gmp-4.2.2.tar.bz2 (it will
be unpacked and built as necessary).
Version 4.2.2 has not been extensively tested with I2P. If you would like
to use a well-tested version, get gmp-4.1.4.tar.bz2, and edit jbigi/build.sh
to change the version number.
To build the native jbigi and jcpuid libraries for the current host CPU,
simply run sh build.sh and the results will be packaged up into jbigi.jar
and the libjbigi.so library. To test, copy jbigi/lib/libjbigi.so
and jcpuid/lib/freenet/support/CPUInformation/libjcpuid-*.so
to your i2p/ directory. You can also copy jbigi.jar to the i2p/lib/ directory;
it will be used only if the router fails to load the native library.
To build the native jbigi libraries for all supported CPUs (on the current OS),
go into jbigi/ and run build-all.sh (the results will be under jbigi/lib/)
After copying the files to the i2p/ directory,
to run a speed test comparing the native library to the java library,
run the shell script below.
-----------------
#!/bin/sh
export I2P=~/i2p
java -cp $I2P/lib/i2p.jar:$I2P/lib/jbigi.jar net.i2p.util.NativeBigInteger

0
core/c/build.sh Normal file → Executable file
View File

7
core/c/jbigi/build-all.sh Normal file → Executable file
View File

@@ -12,8 +12,9 @@ FreeBSD*)
exit;;
esac
echo "Extracting GMP..."
tar -xjf gmp-4.1.4.tar.bz2
VER=4.2.2
echo "Extracting GMP Version $VER ..."
tar -xjf gmp-$VER.tar.bz2
echo "Building..."
mkdir bin
mkdir lib
@@ -24,7 +25,7 @@ for x in none pentium pentiummmx pentium2 pentium3 pentium4 k6 k62 k63 athlon
do
mkdir bin/$x
cd bin/$x
../../gmp-4.1.4/configure --build=$x
../../gmp-$VER/configure --build=$x
make
sh ../../build_jbigi.sh static
case `uname -sr` in

9
core/c/jbigi/build.sh Normal file → Executable file
View File

@@ -1,9 +1,10 @@
#/bin/sh
echo "Building the jbigi library with GMP"
VER=4.2.2
echo "Building the jbigi library with GMP Version $VER"
echo "Extracting GMP..."
tar -xjf gmp-4.1.4.tar.bz2
tar -xjf gmp-$VER.tar.bz2
echo "Building..."
mkdir -p lib/
mkdir -p bin/local
@@ -11,9 +12,9 @@ cd bin/local
case `uname -sr` in
Darwin*)
# --with-pic is required for static linking
../../gmp-4.1.4/configure --with-pic;;
../../gmp-$VER/configure --with-pic;;
*)
../../gmp-4.1.4/configure;;
../../gmp-$VER/configure;;
esac
make
sh ../../build_jbigi.sh static

0
core/c/jbigi/build_jbigi.sh Normal file → Executable file
View File

0
core/c/jcpuid/build.sh Normal file → Executable file
View File

View File

@@ -14,8 +14,8 @@ package net.i2p;
*
*/
public class CoreVersion {
public final static String ID = "$Revision: 1.71 $ $Date: 2007-03-17 16:19:10 $";
public final static String VERSION = "0.6.1.29";
public final static String ID = "$Revision: 1.72 $ $Date: 2007-08-23 19:33:31 $";
public final static String VERSION = "0.6.1.33";
public static void main(String args[]) {
System.out.println("I2P Core version: " + VERSION);

View File

@@ -0,0 +1,146 @@
/*
* By zzz 2008, released into the public domain
* with no warranty of any kind, either expressed or implied.
*/
package net.i2p.client.naming;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.util.EepGet;
import net.i2p.util.Log;
/**
* A network-based naming service using HTTP, with in-memory caching.
* Fetches from one or more remote (in-i2p) CGI services using HTTP GET.
*
* The remote HTTP service takes a CGI parameter and must return (only) the
* 516-byte Base64 destination, or hostname=dest.
* A trailing \n or \r\n is acceptable.
*
* Should be used from MetaNamingService, after HostsTxtNamingService.
* Cannot be used as the only NamingService! Be sure any naming service hosts
* are in hosts.txt.
*
* Sample config to put in configadvanced.jsp (restart required):
*
* i2p.naming.impl=net.i2p.client.naming.MetaNamingService
* i2p.nameservicelist=net.i2p.client.naming.HostsTxtNamingService,net.i2p.client.naming.EepGetNamingService
* i2p.naming.eepget.list=http://namingservice.i2p/cgi-bin/lkup.cgi?host=,http://i2host.i2p/cgi-bin/i2hostquery?
*
*/
public class EepGetNamingService extends NamingService {
private final static String PROP_EEPGET_LIST = "i2p.naming.eepget.list";
private final static String DEFAULT_EEPGET_LIST = "http://i2host.i2p/cgi-bin/i2hostquery?";
private static Properties _hosts;
private final static Log _log = new Log(EepGetNamingService.class);
/**
* The naming service should only be constructed and accessed through the
* application context. This constructor should only be used by the
* appropriate application context itself.
*
*/
public EepGetNamingService(I2PAppContext context) {
super(context);
_hosts = new Properties();
}
private List getURLs() {
String list = _context.getProperty(PROP_EEPGET_LIST, DEFAULT_EEPGET_LIST);
StringTokenizer tok = new StringTokenizer(list, ",");
List rv = new ArrayList(tok.countTokens());
while (tok.hasMoreTokens())
rv.add(tok.nextToken());
return rv;
}
public Destination lookup(String hostname) {
// If it's long, assume it's a key.
if (hostname.length() >= DEST_SIZE)
return lookupBase64(hostname);
hostname = hostname.toLowerCase();
// check the cache
String key = _hosts.getProperty(hostname);
if (key != null) {
_log.error("Found in cache: " + hostname);
return lookupBase64(key);
}
List URLs = getURLs();
if (URLs.size() == 0)
return null;
// prevent lookup loops - this cannot be the only lookup service
for (int i = 0; i < URLs.size(); i++) {
String url = (String)URLs.get(i);
if (url.startsWith("http://" + hostname + "/")) {
_log.error("Lookup loop: " + hostname);
return null;
}
}
// lookup
for (int i = 0; i < URLs.size(); i++) {
String url = (String)URLs.get(i);
key = fetchAddr(url, hostname);
if (key != null) {
_log.error("Success: " + url + hostname);
_hosts.setProperty(hostname, key); // cache
return lookupBase64(key);
}
}
return null;
}
private static final int DEST_SIZE = 516; // Std. Base64 length (no certificate)
private static final int MAX_RESPONSE = DEST_SIZE + 68 + 10; // allow for hostname= and some trailing stuff
private String fetchAddr(String url, String hostname) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(MAX_RESPONSE);
try {
// Do a proxied eepget into our ByteArrayOutputStream with 0 retries
EepGet get = new EepGet(_context, true, "localhost", 4444, 0, DEST_SIZE, MAX_RESPONSE,
null, baos, url + hostname, false, null, null);
// 10s header timeout, 15s total timeout, unlimited inactivity timeout
if (get.fetch(10*1000l, 15*1000l, -1l)) {
if (baos.size() < DEST_SIZE) {
_log.error("Short response: " + url + hostname);
return null;
}
String key = baos.toString();
if (key.startsWith(hostname + "=")) // strip hostname=
key = key.substring(hostname.length() + 1);
key = key.substring(0, DEST_SIZE); // catch IndexOutOfBounds exception below
if (!key.endsWith("AAAA")) {
_log.error("Invalid key: " + url + hostname);
return null;
}
if (key.replaceAll("[a-zA-Z0-9~-]", "").length() != 0) {
_log.error("Invalid chars: " + url + hostname);
return null;
}
return key;
}
_log.error("Fetch failed from: " + url + hostname);
return null;
} catch (Throwable t) {
_log.error("Error fetching the addr", t);
}
_log.error("Caught from: " + url + hostname);
return null;
}
public String reverseLookup(Destination dest) {
return null;
}
}

View File

@@ -0,0 +1,137 @@
/*
* By zzz 2008, released into the public domain
* with no warranty of any kind, either expressed or implied.
*/
package net.i2p.client.naming;
import java.io.InputStream;
import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.util.Exec;
import net.i2p.util.Log;
/**
* An interface to an external naming service program, with in-memory caching.
* This can be used as a simple and flexible way to experiment with
* alternative naming systems.
*
* The external command takes a hostname argument and must return (only) the
* 516-byte Base64 destination, or hostname=dest, on stdout.
* A trailing \n or \r\n is acceptable.
* The command must exit 0 on success. Nonzero on failure is optional.
*
* The external command can do local and/or remote (via i2p or not) lookups.
* No timeouts are implemented here - the author of the external program
* must ensure that the program returns in a reasonable amount of time -
* (15 sec max suggested)
*
* Can be used from MetaNamingService, (e.g. after HostsTxtNamingService),
* or as the sole naming service.
*
* Sample chained config to put in configadvanced.jsp (restart required):
*
* i2p.naming.impl=net.i2p.client.naming.MetaNamingService
* i2p.nameservicelist=net.i2p.client.naming.HostsTxtNamingService,net.i2p.client.naming.ExecNamingService
* i2p.naming.exec.command=/usr/local/bin/i2presolve
*
* Sample unchained config to put in configadvanced.jsp (restart required):
*
* i2p.naming.impl=net.i2p.client.naming.ExecNamingService
* i2p.naming.exec.command=/usr/local/bin/i2presolve
*
*/
public class ExecNamingService extends NamingService {
private final static String PROP_EXEC_CMD = "i2p.naming.exec.command";
private final static String DEFAULT_EXEC_CMD = "/usr/local/bin/i2presolve";
private final static String PROP_SHELL_CMD = "i2p.naming.exec.shell";
private final static String DEFAULT_SHELL_CMD = "/bin/bash";
private static Properties _hosts;
private final static Log _log = new Log(ExecNamingService.class);
/**
* The naming service should only be constructed and accessed through the
* application context. This constructor should only be used by the
* appropriate application context itself.
*
*/
public ExecNamingService(I2PAppContext context) {
super(context);
_hosts = new Properties();
}
public Destination lookup(String hostname) {
// If it's long, assume it's a key.
if (hostname.length() >= DEST_SIZE)
return lookupBase64(hostname);
hostname = hostname.toLowerCase();
// check the cache
String key = _hosts.getProperty(hostname);
if (key != null) {
_log.error("Found in cache: " + hostname);
return lookupBase64(key);
}
// lookup
key = fetchAddr(hostname);
if (key != null) {
_log.error("Success: " + hostname);
_hosts.setProperty(hostname, key); // cache
return lookupBase64(key);
}
return null;
}
private static final int DEST_SIZE = 516; // Std. Base64 length (no certificate)
private static final int MAX_RESPONSE = DEST_SIZE + 68 + 10; // allow for hostname= and some trailing stuff
private String fetchAddr(String hostname) {
String[] commandArr = new String[3];
commandArr[0] = _context.getProperty(PROP_SHELL_CMD, DEFAULT_SHELL_CMD);
commandArr[1] = "-c";
String command = _context.getProperty(PROP_EXEC_CMD, DEFAULT_EXEC_CMD) + " " + hostname;
commandArr[2] = command;
try {
Process get = Runtime.getRuntime().exec(commandArr);
get.waitFor();
int exitValue = get.exitValue();
if (exitValue != 0) {
_log.error("Exit " + exitValue + " from " + commandArr[0] + " " + commandArr[1] + " \"" + command + "\"");
return null;
}
InputStream is = get.getInputStream();
byte[] input = new byte[MAX_RESPONSE];
int count = is.read(input);
is.close();
if (count < DEST_SIZE) {
_log.error("Short response: " + command);
return null;
}
String key = new String(input);
if (key.startsWith(hostname + "=")) // strip hostname=
key = key.substring(hostname.length() + 1);
key = key.substring(0, DEST_SIZE); // catch IndexOutOfBounds exception below
if (!key.endsWith("AAAA")) {
_log.error("Invalid key: " + command);
return null;
}
if (key.replaceAll("[a-zA-Z0-9~-]", "").length() != 0) {
_log.error("Invalid chars: " + command);
return null;
}
return key;
} catch (Throwable t) {
_log.error("Error fetching the addr", t);
}
return null;
}
public String reverseLookup(Destination dest) {
return null;
}
}

View File

@@ -9,8 +9,10 @@ package net.i2p.client.naming;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
@@ -54,6 +56,10 @@ public class HostsTxtNamingService extends NamingService {
}
public Destination lookup(String hostname) {
// If it's long, assume it's a key.
if (hostname.length() >= 516)
return lookupBase64(hostname);
// check the list each time, reloading the file on each
// lookup
@@ -79,12 +85,32 @@ public class HostsTxtNamingService extends NamingService {
}
// not found, continue to the next file
}
// If we can't find name in any of the hosts files,
// assume it's a key.
return lookupBase64(hostname);
return null;
}
public String reverseLookup(Destination dest) {
String destkey = dest.toBase64();
List filenames = getFilenames();
for (int i = 0; i < filenames.size(); i++) {
String hostsfile = (String)filenames.get(i);
Properties hosts = new Properties();
try {
File f = new File(hostsfile);
if ( (f.exists()) && (f.canRead()) ) {
DataHelper.loadProps(hosts, f, true);
Set keyset = hosts.keySet();
Iterator iter = keyset.iterator();
while (iter.hasNext()) {
String host = (String)iter.next();
String key = hosts.getProperty(host);
if (destkey.equals(key))
return host;
}
}
} catch (Exception ioe) {
_log.error("Error loading hosts file " + hostsfile, ioe);
}
}
return null;
}
}
}

View File

@@ -24,7 +24,7 @@ public abstract class NamingService {
/** what classname should be used as the naming service impl? */
public static final String PROP_IMPL = "i2p.naming.impl";
private static final String DEFAULT_IMPL = "net.i2p.client.naming.MetaNamingService";
private static final String DEFAULT_IMPL = "net.i2p.client.naming.HostsTxtNamingService";
/**
@@ -89,4 +89,4 @@ public abstract class NamingService {
}
return instance;
}
}
}

View File

@@ -60,6 +60,45 @@ jP69nPbh4KLGhF+SD0+0bW4=
=npPe
-----END PGP SIGNATURE-----
*/
/*
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
*/
/* zzz's key */
private static final String DEFAULT_TRUSTED_KEY2 =
"lT54eq3SH0TWWwQ1wgH6XPelIno7wH7UfiZOpQg-ZuxdNhc4UjjrohKdK" +
"Zqfswt1ANPnmOlMewLGBESl7kJB9c5sByz~IOlNyz5BMLRC~R~ZC9QI4W" +
"XwUBYW8BhYO2mkvtdOrcy690lDkwzdf5xLxlCBpQlTaLYzQVjVWBcvbCA=";
/*
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFHdupcQVV2uqduC+0RAocuAKCR4ILLuz3RB8QT7zkadmS2LmFuMwCgweqG
lFm5Fqx/iW5+k0QaQZ3W9mY=
=V3i7
-----END PGP SIGNATURE-----
*/
/*
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
*/
/* Complication's key */
private static final String DEFAULT_TRUSTED_KEY3 =
"JHFA0yXUgKtmhajXFZH9Nk62OPRHbvvQHTi8EANV-D~3tjLjaz9p9cs6F" +
"s8W3FSLfUwsQeFg7dfVSQQZga~1jMjboo94vIcm3j6XbW4mbcorVQ74uP" +
"jd8EA1AQhJ6bBTxDAFk~6fVDOdhHT0Wo5CcUn7v8bAYY3x3UWiL8Remx0=";
/*
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFHphOV+h38a3n8zjMRAll+AJ9KA6WiDJcTN4qfrslSemUMr+FBrwCeM8pF
D8usM7Dxp5yrDrCYZ5AIijc=
=SrXI
-----END PGP SIGNATURE-----
*/
private static final String VALID_VERSION_CHARS = "0123456789.";
private static final int VERSION_BYTES = 16;
private static final int HEADER_BYTES = Signature.SIGNATURE_BYTES + VERSION_BYTES;
@@ -92,14 +131,18 @@ jP69nPbh4KLGhF+SD0+0bW4=
String propertyTrustedKeys = context.getProperty(PROP_TRUSTED_KEYS);
if ( (propertyTrustedKeys != null) && (propertyTrustedKeys.length() > 0) ) {
StringTokenizer propertyTrustedKeysTokens = new StringTokenizer(propertyTrustedKeys, ",");
StringTokenizer propertyTrustedKeysTokens = new StringTokenizer(propertyTrustedKeys, " ,\r\n");
while (propertyTrustedKeysTokens.hasMoreTokens())
_trustedKeys.add(propertyTrustedKeysTokens.nextToken().trim());
} else {
_trustedKeys.add(DEFAULT_TRUSTED_KEY);
_trustedKeys.add(DEFAULT_TRUSTED_KEY2);
_trustedKeys.add(DEFAULT_TRUSTED_KEY3);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("TrustedUpdate created, trusting " + _trustedKeys.size() + " keys.");
}
/**
@@ -180,6 +223,7 @@ jP69nPbh4KLGhF+SD0+0bW4=
private static final void genKeysCLI(String publicKeyFile, String privateKeyFile) {
FileOutputStream fileOutputStream = null;
_context = I2PAppContext.getGlobalContext();
try {
Object signingKeypair[] = _context.keyGenerator().generateSigningKeypair();
SigningPublicKey signingPublicKey = (SigningPublicKey) signingKeypair[0];
@@ -273,7 +317,26 @@ jP69nPbh4KLGhF+SD0+0bW4=
public ArrayList getTrustedKeys() {
return _trustedKeys;
}
/**
* Fetches the trusted keys for the current instance.
*
* @return A <code>String</code> containing the trusted keys,
* delimited by CR LF line breaks.
*/
public String getTrustedKeysString() {
StringBuffer buf = new StringBuffer(1024);
for (int i = 0; i < _trustedKeys.size(); i++) {
// If something already buffered, first add line break.
if (buf.length() > 0) buf.append("\r\n");
buf.append((String) _trustedKeys.get(i));
}
return buf.toString();
}
/**
* Reads the version string from a signed update file.
*

View File

@@ -236,6 +236,10 @@ public class DataHelper {
if (split <= 0) continue;
String key = line.substring(0, split);
String val = line.substring(split+1);
// Unescape line breaks after loading.
// Remember: "\" needs escaping both for regex and string.
val = val.replaceAll("\\\\r","\r");
val = val.replaceAll("\\\\n","\n");
if ( (key.length() > 0) && (val.length() > 0) )
if (forceLowerCase)
props.setProperty(key.toLowerCase(), val);
@@ -826,7 +830,7 @@ public class DataHelper {
}
public static String formatDuration(long ms) {
if (ms < 30 * 1000) {
if (ms < 5 * 1000) {
return ms + "ms";
} else if (ms < 5 * 60 * 1000) {
return (ms / 1000) + "s";

View File

@@ -32,6 +32,25 @@ public class StatManager {
public static final String PROP_STAT_FILTER = "stat.logFilters";
public static final String PROP_STAT_FILE = "stat.logFile";
public static final String DEFAULT_STAT_FILE = "stats.log";
public static final String PROP_STAT_FULL = "stat.full";
public static final String DEFAULT_STAT_FULL = "true";
public static final String PROP_STAT_REQUIRED = "stat.required";
/**
* These are all the stats published in netDb, plus those required for the operation of
* the router (many in RouterThrottleImpl), plus those that are on graphs.jsp by default.
* Wildcard ('*') allowed at end of stat only.
* Ignore all the rest of the stats unless stat.full=true.
*/
public static final String DEFAULT_STAT_REQUIRED =
"bw.recvRate,bw.sendBps,bw.sendRate,client.sendAckTime,clock.skew,crypto.elGamal.encrypt," +
"jobQueue.jobLag,netDb.successTime,router.fastPeers," +
"transport.receiveMessageSize,transport.sendMessageSize,transport.sendProcessingTime," +
"tunnel.acceptLoad,tunnel.buildRequestTime,tunnel.rejectOverloaded,tunnel.rejectTimeout" +
"tunnel.buildClientExpire,tunnel.buildClientReject,tunnel.buildClientSuccess," +
"tunnel.buildExploratoryExpire,tunnel.buildExploratoryReject,tunnel.buildExploratorySuccess," +
"tunnel.buildRatio.*,tunnel.buildFailure,tunnel.buildSuccess,tunnel.corruptMessage," +
"tunnel.decryptRequestTime,tunnel.fragmentedDropped,tunnel.participatingMessageCount,"+
"tunnel.participatingTunnels,tunnel.testFailedTime,tunnel.testSuccessTime" ;
/**
* The stat manager should only be constructed and accessed through the
@@ -67,6 +86,7 @@ public class StatManager {
* @param periods array of period lengths (in milliseconds)
*/
public void createFrequencyStat(String name, String description, String group, long periods[]) {
if (ignoreStat(name)) return;
if (_frequencyStats.containsKey(name)) return;
_frequencyStats.put(name, new FrequencyStat(name, description, group, periods));
}
@@ -80,6 +100,7 @@ public class StatManager {
* @param periods array of period lengths (in milliseconds)
*/
public void createRateStat(String name, String description, String group, long periods[]) {
if (ignoreStat(name)) return;
synchronized (_rateStats) {
if (_rateStats.containsKey(name)) return;
RateStat rs = new RateStat(name, description, group, periods);
@@ -165,4 +186,20 @@ public class StatManager {
public String getStatFilter() { return _context.getProperty(PROP_STAT_FILTER); }
public String getStatFile() { return _context.getProperty(PROP_STAT_FILE, DEFAULT_STAT_FILE); }
// Save memory by not creating stats unless they are required for router operation
// Return true if the stat should be ignored.
public boolean ignoreStat(String statName) {
if (_context.getProperty(PROP_STAT_FULL, DEFAULT_STAT_FULL).equalsIgnoreCase("true"))
return false;
String required = _context.getProperty(PROP_STAT_REQUIRED, DEFAULT_STAT_REQUIRED);
String req[] = required.split(",");
for (int i=0; i<req.length; i++) {
if (req[i].equals(statName))
return false;
if (req[i].endsWith("*") && statName.startsWith(req[i].substring(0, req[i].length() - 2)))
return false;
}
return true;
}
}

View File

@@ -18,6 +18,7 @@ import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.SocketTimeout;
/**
* EepGet [-p localhost:4444]
@@ -37,7 +38,10 @@ public class EepGet {
private long _maxSize; // applied both against whole responses and chunks
private String _outputFile;
private OutputStream _outputStream;
/** url we were asked to fetch */
private String _url;
/** the URL we actually fetch from (may differ from the _url in case of redirect) */
private String _actualURL;
private String _postData;
private boolean _allowCaching;
private List _listeners;
@@ -52,45 +56,52 @@ public class EepGet {
private long _bytesRemaining;
private int _currentAttempt;
private String _etag;
private String _lastModified;
private boolean _encodingChunked;
private boolean _notModified;
private String _contentType;
private boolean _transferFailed;
private boolean _headersRead;
private boolean _aborted;
private long _fetchHeaderTimeout;
private long _fetchEndTime;
private long _fetchInactivityTimeout;
private int _redirects;
private String _redirectLocation;
// Constructor 7, calls 3 with: do proxy
public EepGet(I2PAppContext ctx, String proxyHost, int proxyPort, int numRetries, String outputFile, String url) {
this(ctx, true, proxyHost, proxyPort, numRetries, outputFile, url);
}
// Constructor 6, calls 1 with: do proxy, no etag
public EepGet(I2PAppContext ctx, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching) {
this(ctx, true, proxyHost, proxyPort, numRetries, outputFile, url, allowCaching, null);
}
// Constructor 5, calls 3 with: no proxy
public EepGet(I2PAppContext ctx, int numRetries, String outputFile, String url) {
this(ctx, false, null, -1, numRetries, outputFile, url);
}
// Constructor 4, calls 1 with: no proxy, no etag
public EepGet(I2PAppContext ctx, int numRetries, String outputFile, String url, boolean allowCaching) {
this(ctx, false, null, -1, numRetries, outputFile, url, allowCaching, null);
}
// Constructor 3, calls 1 with: do caching, no etag
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url) {
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, outputFile, url, true, null);
}
// Constructor 2, calls 0 with: no output buffer, do caching, no etag
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, String postData) {
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, -1, -1, outputFile, null, url, true, null, postData);
}
// Constructor 1, calls 0 with: no output buffer, no postdata
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching, String etag) {
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, -1, -1, outputFile, null, url, allowCaching, etag, null);
}
// Constructor 0, real constructor
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, String outputFile, String url, boolean allowCaching, String etag, String lastModified) {
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, -1, -1, outputFile, null, url, allowCaching, etag, lastModified, null);
}
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, long minSize, long maxSize, String outputFile, OutputStream outputStream, String url, boolean allowCaching, String etag, String postData) {
this(ctx, shouldProxy, proxyHost, proxyPort, numRetries, minSize, maxSize, outputFile, outputStream, url, allowCaching, etag, null, postData);
}
public EepGet(I2PAppContext ctx, boolean shouldProxy, String proxyHost, int proxyPort, int numRetries, long minSize, long maxSize,
String outputFile, OutputStream outputStream, String url, boolean allowCaching,
String etag, String postData) {
String etag, String lastModified, String postData) {
_context = ctx;
_log = ctx.logManager().getLog(EepGet.class);
_shouldProxy = shouldProxy;
_shouldProxy = (proxyHost != null) && (proxyHost.length() > 0) && (proxyPort > 0) && shouldProxy;
_proxyHost = proxyHost;
_proxyPort = proxyPort;
_numRetries = numRetries;
@@ -99,13 +110,19 @@ public class EepGet {
_outputFile = outputFile; // if outputFile is set, outputStream must be null
_outputStream = outputStream; // if both are set, outputStream overrides outputFile
_url = url;
_actualURL = url;
_postData = postData;
_alreadyTransferred = 0;
_bytesTransferred = 0;
_bytesRemaining = -1;
_currentAttempt = 0;
_transferFailed = false;
_headersRead = false;
_aborted = false;
_fetchHeaderTimeout = 45*1000;
_listeners = new ArrayList(1);
_etag = etag;
_lastModified = lastModified;
}
/**
@@ -198,18 +215,35 @@ public class EepGet {
}
public static interface StatusListener {
/**
* alreadyTransferred - total of all attempts, not including currentWrite
* If nonzero on the first call, a partial file of that length was found
* To track _actual_ transfer if the output file could already exist,
* the listener should keep its own counter,
* or subtract the initial alreadyTransferred value.
* currentWrite - since last call to the listener
* bytesTransferred - includes headers, retries, redirects, ...
* bytesRemaining - on this attempt only, currentWrite already subtracted -
* or -1 if chunked encoding or server does not return a length
*
* Total length should be == alreadyTransferred + currentWrite + bytesRemaining for all calls
*
*/
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url);
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified);
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause);
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt);
public void headerReceived(String url, int currentAttempt, String key, String val);
public void attempting(String url);
}
private class CLIStatusListener implements StatusListener {
private int _markSize;
private int _lineSize;
private long _startedOn;
private long _written;
private long _previousWritten;
private long _lastComplete;
private boolean _firstTime;
private DecimalFormat _pct = new DecimalFormat("00.0%");
private DecimalFormat _kbps = new DecimalFormat("###,000.00");
public CLIStatusListener() {
@@ -219,10 +253,19 @@ public class EepGet {
_markSize = markSize;
_lineSize = lineSize;
_written = 0;
_previousWritten = 0;
_lastComplete = _context.clock().now();
_startedOn = _lastComplete;
_firstTime = true;
}
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
if (_firstTime) {
if (alreadyTransferred > 0) {
_previousWritten = alreadyTransferred;
System.out.println("File found with length " + alreadyTransferred + ", resuming");
}
_firstTime = false;
}
for (int i = 0; i < currentWrite; i++) {
_written++;
if ( (_markSize > 0) && (_written % _markSize == 0) ) {
@@ -235,13 +278,14 @@ public class EepGet {
StringBuffer buf = new StringBuffer(50);
buf.append(" ");
if ( bytesRemaining > 0 ) {
double pct = ((double)alreadyTransferred + (double)_written) / ((double)alreadyTransferred + (double)bytesRemaining);
double pct = ((double)_written + _previousWritten) /
((double)alreadyTransferred + (double)currentWrite + (double)bytesRemaining);
synchronized (_pct) {
buf.append(_pct.format(pct));
}
buf.append(": ");
}
buf.append(_written+alreadyTransferred);
buf.append(_written);
buf.append(" @ ");
double lineKBytes = ((double)_markSize * (double)_lineSize)/1024.0d;
double kbps = lineKBytes/((double)timeToSend/1000.0d);
@@ -252,7 +296,7 @@ public class EepGet {
buf.append(" / ");
long lifetime = _context.clock().now() - _startedOn;
double lifetimeKBps = (1000.0d*(double)(_written+alreadyTransferred)/((double)lifetime*1024.0d));
double lifetimeKBps = (1000.0d*(double)(_written)/((double)lifetime*1024.0d));
synchronized (_kbps) {
buf.append(_kbps.format(lifetimeKBps));
}
@@ -265,32 +309,40 @@ public class EepGet {
}
}
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
long transferred;
if (_firstTime)
transferred = 0;
else
transferred = alreadyTransferred - _previousWritten;
System.out.println();
System.out.println("== " + new Date());
if (notModified) {
System.out.println("== Source not modified since last download");
} else {
if ( bytesRemaining > 0 ) {
System.out.println("== Transfer of " + url + " completed with " + (alreadyTransferred+bytesTransferred)
+ " and " + (bytesRemaining - bytesTransferred) + " remaining");
System.out.println("== Output saved to " + outputFile);
System.out.println("== Transfer of " + url + " completed with " + transferred
+ " transferred and " + (bytesRemaining - bytesTransferred) + " remaining");
} else {
System.out.println("== Transfer of " + url + " completed with " + (alreadyTransferred+bytesTransferred)
System.out.println("== Transfer of " + url + " completed with " + transferred
+ " bytes transferred");
System.out.println("== Output saved to " + outputFile);
}
if (transferred > 0)
System.out.println("== Output saved to " + outputFile + " (" + alreadyTransferred + " bytes)");
}
long timeToSend = _context.clock().now() - _startedOn;
System.out.println("== Transfer time: " + DataHelper.formatDuration(timeToSend));
System.out.println("== ETag: " + _etag);
StringBuffer buf = new StringBuffer(50);
buf.append("== Transfer rate: ");
double kbps = (1000.0d*(double)(_written)/((double)timeToSend*1024.0d));
synchronized (_kbps) {
buf.append(_kbps.format(kbps));
if (_etag != null)
System.out.println("== ETag: " + _etag);
if (transferred > 0) {
StringBuffer buf = new StringBuffer(50);
buf.append("== Transfer rate: ");
double kbps = (1000.0d*(double)(transferred)/((double)timeToSend*1024.0d));
synchronized (_kbps) {
buf.append(_kbps.format(kbps));
}
buf.append("KBps");
System.out.println(buf.toString());
}
buf.append("KBps");
System.out.println(buf.toString());
}
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {
System.out.println();
@@ -299,6 +351,7 @@ public class EepGet {
System.out.println("** Transfered " + bytesTransferred
+ " with " + (bytesRemaining < 0 ? "unknown" : ""+bytesRemaining) + " remaining");
System.out.println("** " + cause.getMessage());
_previousWritten += _written;
_written = 0;
}
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {
@@ -317,6 +370,7 @@ public class EepGet {
buf.append("KBps");
System.out.println(buf.toString());
}
public void attempting(String url) {}
public void headerReceived(String url, int currentAttempt, String key, String val) {}
}
@@ -329,19 +383,52 @@ public class EepGet {
* Blocking fetch, returning true if the URL was retrieved, false if all retries failed
*
*/
public boolean fetch() {
public boolean fetch() { return fetch(_fetchHeaderTimeout); }
/**
* Blocking fetch, timing out individual attempts if the HTTP response headers
* don't come back in the time given. If the timeout is zero or less, this will
* wait indefinitely.
*/
public boolean fetch(long fetchHeaderTimeout) {
return fetch(fetchHeaderTimeout, -1, -1);
}
public boolean fetch(long fetchHeaderTimeout, long totalTimeout, long inactivityTimeout) {
_fetchHeaderTimeout = fetchHeaderTimeout;
_fetchEndTime = (totalTimeout > 0 ? System.currentTimeMillis() + totalTimeout : -1);
_fetchInactivityTimeout = inactivityTimeout;
_keepFetching = true;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Fetching (proxied? " + _shouldProxy + ") url=" + _url);
_log.debug("Fetching (proxied? " + _shouldProxy + ") url=" + _actualURL);
while (_keepFetching) {
SocketTimeout timeout = null;
if (_fetchHeaderTimeout > 0)
timeout = new SocketTimeout(_fetchHeaderTimeout);
final SocketTimeout stimeout = timeout; // ugly
timeout.setTimeoutCommand(new Runnable() {
public void run() {
if (_log.shouldLog(Log.DEBUG))
_log.debug("timeout reached on " + _url + ": " + stimeout);
_aborted = true;
}
});
timeout.setTotalTimeoutPeriod(_fetchEndTime);
try {
sendRequest();
doFetch();
return true;
for (int i = 0; i < _listeners.size(); i++)
((StatusListener)_listeners.get(i)).attempting(_url);
sendRequest(timeout);
timeout.resetTimer();
doFetch(timeout);
timeout.cancel();
if (!_transferFailed)
return true;
break;
} catch (IOException ioe) {
timeout.cancel();
for (int i = 0; i < _listeners.size(); i++)
((StatusListener)_listeners.get(i)).attemptFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt, _numRetries, ioe);
if (_log.shouldLog(Log.WARN))
_log.warn("ERR: doFetch failed " + ioe);
} finally {
if (_out != null) {
try {
@@ -360,51 +447,120 @@ public class EepGet {
_currentAttempt++;
if (_currentAttempt > _numRetries)
break;
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
try {
long delay = _context.random().nextInt(60*1000);
Thread.sleep(5*1000+delay);
} catch (InterruptedException ie) {}
}
for (int i = 0; i < _listeners.size(); i++)
((StatusListener)_listeners.get(i)).transferFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt);
if (_log.shouldLog(Log.WARN))
_log.warn("All attempts failed for " + _url);
return false;
}
/** a single fetch attempt */
private void doFetch() throws IOException {
readHeaders();
/** return true if the URL was completely retrieved */
private void doFetch(SocketTimeout timeout) throws IOException {
_headersRead = false;
_aborted = false;
try {
readHeaders();
} finally {
_headersRead = true;
}
if (_aborted)
throw new IOException("Timed out reading the HTTP headers");
timeout.resetTimer();
if (_fetchInactivityTimeout > 0)
timeout.setInactivityTimeout(_fetchInactivityTimeout);
else
timeout.setInactivityTimeout(60*1000);
if (_redirectLocation != null) {
try {
URL oldURL = new URL(_actualURL);
String query = oldURL.getQuery();
if (query == null) query = "";
if (_redirectLocation.startsWith("http://")) {
if ( (_redirectLocation.indexOf('?') < 0) && (query.length() > 0) )
_actualURL = _redirectLocation + "?" + query;
else
_actualURL = _redirectLocation;
} else {
URL url = new URL(_actualURL);
if (_redirectLocation.startsWith("/"))
_actualURL = "http://" + url.getHost() + ":" + url.getPort() + _redirectLocation;
else
_actualURL = "http://" + url.getHost() + ":" + url.getPort() + "/" + _redirectLocation;
if ( (_actualURL.indexOf('?') < 0) && (query.length() > 0) )
_actualURL = _actualURL + "?" + query;
else
_actualURL = _actualURL;
}
} catch (MalformedURLException mue) {
throw new IOException("Redirected from an invalid URL");
}
_redirects++;
if (_redirects > 5)
throw new IOException("Too many redirects: to " + _redirectLocation);
if (_log.shouldLog(Log.INFO)) _log.info("Redirecting to " + _redirectLocation);
sendRequest(timeout);
doFetch(timeout);
return;
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Headers read completely, reading " + _bytesRemaining);
boolean strictSize = (_bytesRemaining >= 0);
// If minimum or maximum size defined, ensure they aren't exceeded
if ((_minSize > -1) && (_bytesRemaining < _minSize))
if ((_minSize > 0) && (_bytesRemaining < _minSize))
throw new IOException("HTTP response size " + _bytesRemaining + " violates minimum of " + _minSize + " bytes");
if ((_maxSize > -1) && (_bytesRemaining > _maxSize))
throw new IOException("HTTP response size " + _bytesRemaining + " violates maximum of " + _maxSize + " bytes");
int remaining = (int)_bytesRemaining;
byte buf[] = new byte[1024];
while (_keepFetching && ( (remaining > 0) || !strictSize )) {
while (_keepFetching && ( (remaining > 0) || !strictSize ) && !_aborted) {
int toRead = buf.length;
if (strictSize && toRead > remaining)
toRead = remaining;
int read = _proxyIn.read(buf, 0, toRead);
if (read == -1)
break;
timeout.resetTimer();
_out.write(buf, 0, read);
_bytesTransferred += read;
// This seems necessary to properly resume a partial download into a stream,
// as nothing else increments _alreadyTransferred, and there's no file length to check.
// Hopefully this won't break compatibility with existing status listeners
// (cause them to behave weird, or show weird numbers).
_alreadyTransferred += read;
if ((_maxSize > -1) && (_alreadyTransferred + read > _maxSize)) // could transfer a little over maxSize
throw new IOException("Bytes transferred " + (_alreadyTransferred + read) + " violates maximum of " + _maxSize + " bytes");
remaining -= read;
if (remaining==0 && _encodingChunked) {
if(_proxyIn.read()=='\r' && _proxyIn.read()=='\n') {
remaining = (int) readChunkLength();
int char1 = _proxyIn.read();
if (char1 == '\r') {
int char2 = _proxyIn.read();
if (char2 == '\n') {
remaining = (int) readChunkLength();
} else {
_out.write(char1);
_out.write(char2);
_bytesTransferred += 2;
remaining -= 2;
read += 2;
}
} else {
_out.write(char1);
_bytesTransferred++;
remaining--;
read++;
}
}
if (read > 0)
timeout.resetTimer();
if (_bytesRemaining >= read) // else chunked?
_bytesRemaining -= read;
if (read > 0) {
for (int i = 0; i < _listeners.size(); i++)
((StatusListener)_listeners.get(i)).bytesTransferred(
_alreadyTransferred,
@@ -412,16 +568,33 @@ public class EepGet {
_bytesTransferred,
_encodingChunked?-1:_bytesRemaining,
_url);
// This seems necessary to properly resume a partial download into a stream,
// as nothing else increments _alreadyTransferred, and there's no file length to check.
// Do this after calling the listeners to keep the total correct
_alreadyTransferred += read;
}
}
if (_out != null)
_out.close();
_out = null;
if (_aborted)
throw new IOException("Timed out reading the HTTP data");
timeout.cancel();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Done transferring " + _bytesTransferred);
_log.debug("Done transferring " + _bytesTransferred + " (ok? " + !_transferFailed + ")");
if ( (_bytesRemaining == -1) || (remaining == 0) ){
if (_transferFailed) {
// 404, etc - transferFailed is called after all attempts fail, by fetch() above
for (int i = 0; i < _listeners.size(); i++)
((StatusListener)_listeners.get(i)).attemptFailed(_url, _bytesTransferred, _bytesRemaining, _currentAttempt, _numRetries, new Exception("Attempt failed"));
} else if ((_minSize > 0) && (_alreadyTransferred < _minSize)) {
throw new IOException("Bytes transferred " + _alreadyTransferred + " violates minimum of " + _minSize + " bytes");
} else if ( (_bytesRemaining == -1) || (remaining == 0) ) {
for (int i = 0; i < _listeners.size(); i++)
((StatusListener)_listeners.get(i)).transferComplete(
_alreadyTransferred,
@@ -442,32 +615,57 @@ public class EepGet {
boolean read = DataHelper.readLine(_proxyIn, buf);
if (!read) throw new IOException("Unable to read the first line");
int responseCode = handleStatus(buf.toString());
boolean redirect = false;
if (_log.shouldLog(Log.DEBUG))
_log.debug("rc: " + responseCode + " for " + _actualURL);
boolean rcOk = false;
switch (responseCode) {
case 200: // full
if (_outputStream != null) _out = _outputStream;
else _out = new FileOutputStream(_outputFile, false);
if (_outputStream != null)
_out = _outputStream;
else
_out = new FileOutputStream(_outputFile, false);
_alreadyTransferred = 0;
rcOk = true;
break;
case 206: // partial
if (_outputStream != null) _out = _outputStream;
else _out = new FileOutputStream(_outputFile, true);
if (_outputStream != null)
_out = _outputStream;
else
_out = new FileOutputStream(_outputFile, true);
rcOk = true;
break;
case 301: // various redirections
case 302:
case 303:
case 307:
_alreadyTransferred = 0;
rcOk = true;
redirect = true;
break;
case 304: // not modified
_bytesRemaining = 0;
_keepFetching = false;
_notModified = true;
return;
return;
case 404: // not found
_keepFetching = false;
_transferFailed = true;
return;
case 416: // completed (or range out of reach)
_bytesRemaining = 0;
_keepFetching = false;
return;
default:
rcOk = false;
_transferFailed = true;
}
// clear out the arguments, as we use the same variables for return values
_etag = null;
_lastModified = null;
buf.setLength(0);
byte lookahead[] = new byte[3];
while (true) {
@@ -500,6 +698,7 @@ public class EepGet {
if (_encodingChunked) {
_bytesRemaining = readChunkLength();
}
if (!redirect) _redirectLocation = null;
return;
}
break;
@@ -589,11 +788,15 @@ public class EepGet {
}
} else if (key.equalsIgnoreCase("ETag")) {
_etag = val.trim();
} else if (key.equalsIgnoreCase("Last-Modified")) {
_lastModified = val.trim();
} else if (key.equalsIgnoreCase("Transfer-encoding")) {
if (val.indexOf("chunked") != -1)
_encodingChunked = true;
} else if (key.equalsIgnoreCase("Content-Type")) {
_contentType=val;
} else if (key.equalsIgnoreCase("Location")) {
_redirectLocation=val.trim();
} else {
// ignore the rest
}
@@ -616,13 +819,13 @@ public class EepGet {
private static final byte NL = '\n';
private boolean isNL(byte b) { return (b == NL); }
private void sendRequest() throws IOException {
private void sendRequest(SocketTimeout timeout) throws IOException {
if (_outputStream != null) {
// We are reading into a stream supplied by a caller,
// for which we cannot easily determine how much we've written.
// Assume that _alreadyTransferred holds the right value
// (we should never be restarted to work on an old stream).
} else {
} else {
File outFile = new File(_outputFile);
if (outFile.exists())
_alreadyTransferred = outFile.length();
@@ -630,24 +833,34 @@ public class EepGet {
String req = getRequest();
if (_proxyIn != null) try { _proxyIn.close(); } catch (IOException ioe) {}
if (_proxyOut != null) try { _proxyOut.close(); } catch (IOException ioe) {}
if (_proxy != null) try { _proxy.close(); } catch (IOException ioe) {}
if (_shouldProxy) {
_proxy = new Socket(_proxyHost, _proxyPort);
} else {
try {
URL url = new URL(_url);
String host = url.getHost();
int port = url.getPort();
if (port == -1)
port = 80;
_proxy = new Socket(host, port);
URL url = new URL(_actualURL);
if ("http".equals(url.getProtocol())) {
String host = url.getHost();
int port = url.getPort();
if (port == -1)
port = 80;
_proxy = new Socket(host, port);
} else {
throw new IOException("URL is not supported:" + _actualURL);
}
} catch (MalformedURLException mue) {
throw new IOException("Request URL is invalid");
}
}
_proxyIn = _proxy.getInputStream();
_proxyOut = _proxy.getOutputStream();
_proxyOut.write(req.toString().getBytes());
timeout.setSocket(_proxy);
_proxyOut.write(DataHelper.getUTF8(req.toString()));
_proxyOut.flush();
if (_log.shouldLog(Log.DEBUG))
@@ -659,12 +872,24 @@ public class EepGet {
boolean post = false;
if ( (_postData != null) && (_postData.length() > 0) )
post = true;
URL url = new URL(_actualURL);
String proto = url.getProtocol();
String host = url.getHost();
int port = url.getPort();
String path = url.getPath();
String query = url.getQuery();
if (query != null)
path = path + "?" + query;
if (!path.startsWith("/"))
path = "/" + path;
if ( (port == 80) || (port == 443) || (port <= 0) ) path = proto + "://" + host + path;
else path = proto + "://" + host + ":" + port + path;
if (_log.shouldLog(Log.DEBUG)) _log.debug("Requesting " + path);
if (post) {
buf.append("POST ").append(_url).append(" HTTP/1.1\r\n");
buf.append("POST ").append(_actualURL).append(" HTTP/1.1\r\n");
} else {
buf.append("GET ").append(_url).append(" HTTP/1.1\r\n");
buf.append("GET ").append(_actualURL).append(" HTTP/1.1\r\n");
}
URL url = new URL(_url);
buf.append("Host: ").append(url.getHost()).append("\r\n");
if (_alreadyTransferred > 0) {
buf.append("Range: bytes=");
@@ -677,11 +902,16 @@ public class EepGet {
buf.append("Cache-control: no-cache\r\n");
buf.append("Pragma: no-cache\r\n");
}
if (_etag != null) {
if ((_etag != null) && (_alreadyTransferred <= 0)) {
buf.append("If-None-Match: ");
buf.append(_etag);
buf.append("\r\n");
}
if ((_lastModified != null) && (_alreadyTransferred <= 0)) {
buf.append("If-Modified-Since: ");
buf.append(_lastModified);
buf.append("\r\n");
}
if (post)
buf.append("Content-length: ").append(_postData.length()).append("\r\n");
buf.append("Connection: close\r\n\r\n");
@@ -696,6 +926,10 @@ public class EepGet {
return _etag;
}
public String getLastModified() {
return _lastModified;
}
public boolean getNotModified() {
return _notModified;
}

View File

@@ -36,7 +36,8 @@ public class EepGetScheduler implements EepGet.StatusListener {
public void fetch(boolean shouldBlock) {
//Checking for a valid index is done in fetchNext, so we don't have to worry about it.
if (shouldBlock) {
fetchNext();
while (_curURL < _urls.size())
fetchNext();
} else {
fetch();
}
@@ -77,6 +78,7 @@ public class EepGetScheduler implements EepGet.StatusListener {
_listener.transferFailed(url, bytesTransferred, bytesRemaining, currentAttempt);
fetchNext();
}
public void attempting(String url) { _listener.attempting(url); }
public void headerReceived(String url, int attemptNum, String key, String val) {}
}

View File

@@ -207,11 +207,11 @@ public class SimpleTimer {
_occurredEventCount += eventsToFire.size();
} else {
_occurredTime = now;
if (_occurredEventCount > 1000) {
if (_occurredEventCount > 2500) {
StringBuffer buf = new StringBuffer(128);
buf.append("Too many simpleTimerJobs (").append(_occurredEventCount);
buf.append(") in a second!");
_log.log(Log.CRIT, buf.toString());
_log.log(Log.WARN, buf.toString());
}
_occurredEventCount = 0;
}

View File

@@ -0,0 +1,71 @@
package net.i2p.util;
import java.io.IOException;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SocketTimeout implements SimpleTimer.TimedEvent {
private Socket _targetSocket;
private long _startTime;
private long _inactivityDelay;
private long _lastActivity;
private long _totalTimeoutTime;
private boolean _cancelled;
private Runnable _command;
public SocketTimeout(long delay) { this(null, delay); }
public SocketTimeout(Socket socket, long delay) {
_inactivityDelay = delay;
_targetSocket = socket;
_cancelled = false;
_lastActivity = _startTime = System.currentTimeMillis();
_totalTimeoutTime = -1;
SimpleTimer.getInstance().addEvent(SocketTimeout.this, delay);
}
public void timeReached() {
if (_cancelled) return;
if ( ( (_totalTimeoutTime > 0) && (_totalTimeoutTime <= System.currentTimeMillis()) ) ||
(_inactivityDelay + _lastActivity <= System.currentTimeMillis()) ) {
if (_targetSocket != null) {
try {
if (!_targetSocket.isClosed())
_targetSocket.close();
} catch (IOException ioe) {}
}
if (_command != null) _command.run();
} else {
SimpleTimer.getInstance().addEvent(SocketTimeout.this, _inactivityDelay);
}
}
public void cancel() {
_cancelled = true;
SimpleTimer.getInstance().removeEvent(SocketTimeout.this);
}
public void setSocket(Socket s) { _targetSocket = s; }
public void resetTimer() { _lastActivity = System.currentTimeMillis(); }
public void setInactivityTimeout(long timeout) { _inactivityDelay = timeout; }
public void setTotalTimeoutPeriod(long timeoutPeriod) {
if (timeoutPeriod > 0)
_totalTimeoutTime = _startTime + timeoutPeriod;
else
_totalTimeoutTime = -1;
}
public void setTimeoutCommand(Runnable job) { _command = job; }
private static final SimpleDateFormat _fmt = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSS");
private static String ts(long when) { synchronized (_fmt) { return _fmt.format(new Date(when)); } }
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("started on ");
buf.append(ts(_startTime));
buf.append("idle for ");
buf.append(System.currentTimeMillis() - _lastActivity);
buf.append("ms ");
if (_totalTimeoutTime > 0)
buf.append("total timeout at ").append(ts(_totalTimeoutTime));
buf.append("cancelled? ").append(_cancelled);
return buf.toString();
}
}

View File

@@ -1,4 +1,474 @@
$Id: history.txt,v 1.583 2007-08-13 14:42:59 zzz Exp $
* 2008-04-26 0.6.1.33 released
2008-04-20 zzz
* Outbound message/Reachability:
- Fix a bug from -19 causing the persistent lease selection
removed in -17 to be back again
- Use netDb-listed-unreachable instead of detected-unreachable
for exclusion of unreachable peers from selected leases,
as there are potential anonymity problems with using
detected-unreachable
- Tweak logging some more
* NetDb stats: Remove a couple more including the inefficient stat_identities
2008-04-17 zzz
* Reachability:
- Track unreachable peers persistently
(i.e. separately from shitlist, and not cleared when they contact us)
- Exclude detected unreachable peers from inbound tunnels
- Exclude detected unreachable peers from selected leases
- Exclude detected unreachable floodfill peers from lookups
- Show unreachable status on profiles.jsp
2008-04-16 zzz
* SSU/Reachability:
- Extend shitlist time from 4-8m to 40-60m
- Add some shitlist logging
- Don't shitlist twice when unreachable on all transports
- Exclude netDb-listed unreachable peers from inbound tunnels;
this won't help much since there are very few of these now
- Remove 10s delay on inbound UDP connections used for the
0.6.1.10 transition
- Track and display UDP connection direction on peers.jsp
- Show shitlist status in-line on profiles.jsp
2008-04-15 zzz
* SSU Reachability/PeerTestManager:
- Back out strict peer ordering until we fix SSU
- Back out persistent lease selection until we fix SSU
- Fix detection of UDP REJECT_UNSOLICITED by recording status on expiration
- Increase known Charlie time to 10m; 3m wasn't enough
- Don't continue retransmitting peer test if we know Charlie
- Don't run multiple peer tests at once
- Tighten test frequency range to 6.5-19.5m, was 0-26m
2008-04-12 zzz
* Addressbook: Disallow '.-' and '-.' in host names
* NTCP: Don't drop a connection unless both directions are idle;
Fix idle time for outbound connections
* Outbound message: Make sure cached lease is in current leaseSet
* Stats: Put all NetworkDatabase stats in same group
* TunnelPool: Stop building tunnels and leaseSets after client shutdown
* i2psnark: Add locking to prevent two I2CP connections
2008-04-07 zzz
* i2psnark:
- Implement upstream bandwidth limiting
- Fix a rare NPE at startup/shutdown
- Really increase retries for .torrent fetch
* profiles.jsp: Minor cleanup
* DataHelper: Only format < 5s as ms
* Eepget: Fix percentage output on command line eepget retries
* Lower partipating message priority from 400 to 200
* NTCP: Add a debug message
* Outbound message: Minor cleanup
2008-03-30 zzz
* ExploratoryPeerSelector: Try NonFailing even more
* HostsTxtNamingService: Add reverse lookup support
* Outbound message: Minor cleanup
* i2psnark TrackerClient: Minor cleanup
* checklist.txt: Minor edit
* hosts.txt: Add perv.i2p, false.i2p, mtn.i2p2.i2p
* i2ptunnel.config: Change CVS client to mtn
* netdb.jsp: Show leaseSet destinations using reverse lookup
* profiles.jsp: First cut at showing floodfill data
2008-03-27 zzz
* Send messages for the same destination to the same inbound
lease to reduce out-of-order delivery.
* ExploratoryPeerSelector: Back out the floodfill peer exclusion
for now, as it prevents speed rating of those peers
2008-03-26 zzz
* ReseedHandler: Support multiple urls,
add netdb.i2p2.de as a 2nd default
2008-03-25 zzz
* i2psnark:
- Add support for secondary open trackers
- Refactor and simplify the TrackerClient code
- Add welterde's tracker to the default list
- Don't have eepget retry announces
- Slow down tracker contacts if they've failed for a while
- Add some debug support showing connections (?p=2)
* hosts.txt: Add nickyb.i2p, tracker.welterde.i2p
2008-03-22 zzz
* NewsFetcher: Fix bug causing fetch every 10m
2008-03-22 zzz
* Tunnel Testing:
- Fix counting so it really takes 4 consecutive failures
rather than 4 total to remove a tunnel
- Credit or blame goes to the exploratory tunnel as well
as the tunnel being tested
- Adjust tunnel test timeout based on tunnel length
* ExploratoryPeerSelector: Tweak logging
* ProfileOrganizer: Adjust integration calculation again
* build.xml: Add to help
* checklist.txt: Tweak
* readme.html: Fix forum links
* netDb: Remove tunnel.testFailedTime
2008-03-19 zzz
* ExploratoryPeerSelector:
- Exclude floodfill peers
- Tweak the HighCap vs. NonFailing decision; try NonFailing
at least a minimum % of the time
* i2psnark: Increase retries for .torrent fetch
* IRC Proxy: Prevent mIRC from sending an alternate DCC request
containing an IP
* readme.html: Reorder some items
* Stats: Add some more required stats
* Streaming lib: Fix slow start to be exponential growth,
fix congestion avoidance to be linear growth.
Should speed up local connections a lot, and remote
connections a little.
2008-03-14 zzz
* Floodfill Search:
- Prefer heard-from, unfailing, unshitlisted floodfill peers
2008-03-14 zzz
* ProfileOrganizer:
- Use more recent stats to calculate integration
- Show that fast peers are also high-capacity on profiles.jsp
* readme.html: Update Syndie link
* TunnelPool: Update comments
* netDb: Report 1-2h uptime as 90m to further frustrate tracking,
get rid of the 60s tunnel stats
(effective as of .33 to provide cover)
2008-03-13 zzz
* Floodfill Search:
- Fix a bug that caused a single FloodfillOnlySearchJob
instance to be run multiple times, with unpredictable
results
- Select ff peers randomly to improve reliability
- Add some bulletproofing
2008-03-11 zzz
* ProfileOrganizer:
- Don't require a peer to be high-capacity to be
well-integrated (not used for anything right now,
but want to get it right for possible floodfill verification)
- Don't fall back to median for high-capacity threshold
if the mean is higher than the median, this prevents
frequent large high-capacity counts
- Fix high-capacity selector that picked one too many
* Console: put well-integrated count back in the summary
2008-03-10 zzz
* EepGet: Fix byte count for bytesTransferred status listeners
(fixes command line status)
* UpdateHandler:
- Fix byte count display
- Display final status on router console
- Don't allow multiple update jobs to queue up
- Increase max retries
- Code cleanup
- Don't show 'check for update' button when update in progress
- Enhance error messages
* NetDb: Comment out published netDb stats disabled for .32
2008-03-08 zzz
* TunnelPeerSelectors: Implement strict ordering of peers,
based on XOR distance from a random hash
separately generated for each tunnel pool
2008-03-07 zzz
* Naming: Optimize lookups for a destkey
* ProfileOrganizer, TunnelPoolSettings, ClientPeerSelector:
- Prevent peers with matching IPs from joining same tunnel.
Match 0-4 bytes of IP (0=off, 1=most restrictive, 4=least).
Default is 2 (disallow routers in same /16).
Set with router.defaultPool.IPRestriction=x
- Comment out unused RebuildPeriod pool setting
- Add random key to pool in preparation for XOR peer ordering
* SusiMail: Add 'Create Account' link
* TunnelDispatcher: Change a common wtf error to a warn
2008-03-05 zzz
* Naming: Make HostsTxt the sole default NamingService
(was Meta = PetName + HostsTxt)
* Naming: Add two new experimental NamingServices, EepGet and Exec,
not enabled by default -
see source comments in core/java/src/net/i2p/client/naming
for configuration instructions
* i2psnark: Don't do a naming lookup for Base64 destkeys
* i2psnark: Add a StartAll button
* Stats: Add code to disable most stats to save memory.
Set on configstats.jsp or set stat.full=false to disable the stats.
(true by default for now)
2008-03-09 Complication
* Give the Jetty build file ability to ask permission
before downloading the Jetty archive from the web,
and to verify its SHA1 + MD5 hashes. Adjust the main build file
in accordance with this change.
* Improve the release checklist.
* 2008-03-09 0.6.1.32 released
2008-03-07 zzz
* Update news and version numbers
2008-03-01 zzz
* Fix netdb.knownLeaseSets count reported by floodfill routers
(was broken by -3)
2008-02-27 zzz
* i2ptunnel: Add 3-hop option to edit.jsp to match configtunnels.jsp
* i2psnark: Remove orion and gaytorrents from default tracker list
* Remove orion from jump list and from eepsite_index.html
* Jbigi: Change jbigi version to 4.2.2 in build scripts - tested by amiga
* Capitalize OutboundMessageDistributor job name
* TunnelPool: Add a warning if all tunnels are backlogged
2008-02-26 zzz
* Reintroduce NTCP backlog pushback, with switch back to
previous tunnel when no longer backlogged
* Catch an nio exception in an NTCP logging statement if loglevel is WARN
* IRC Proxy: terminate all messages with \r\n (thanks TrivialPursuit!)
2008-02-21 zzz
* Raise inbound default bandwidth to 32KBps
* Fix config.jsp that showed 0KBps share bandwidth by default
2008-02-19 zzz
* Addressbook: Disallow '--' in host names except in IDN,
add some reserved host names
* I2PTunnel: Clarify edit form
* NetDb: Remove many stats from netDb, effective as of .32
* profiles.jsp: Display capabilities
* Tunnels: Enforce max tunnel length of 8, catch an index error
http://forum.i2p/viewtopic.php?t=2561
2008-02-16 zzz
* Fix race in TunnelDispatcher which caused
participating tunnel count to seesaw -
should increase network capacity
* Leave participating tunnels in 10s batches for efficiency
* Update participating tunnel ratestat when leaving a tunnel too,
to generate a smoother graph
* Fix tunnel.participatingMessageCount stat to include all
participating tunnels, not just outbound endpoints
* Simplify Expire Tunnel job name
2008-02-13 zzz
* PersistentDataStore: Write out 300 records every 10 min
rather than 1 every 10 sec;
Don't store leasesets to disk or read them in
* Combine rates for pools with the same length setting
in the new tunnel build algorithm
* Clarify a log message in the UpdateHandler
2008-02-13 zzz
* Make graphs clickable to get larger graphs
* Change SimpleTimer CRIT to a WARN, increase threshold
* Checklist update
2008-02-11 welterde
* Fix an NPE in UDP http://forum.i2p/viewtopic.php?t=2545
2008-02-10 zzz
* Add new tunnel build algorithm (preliminary)
* Change NTCP backlogged message from error to warning
* Checklist updates
* 2008-02-10 0.6.1.31 released
2008-02-10 Complication
* Update news and version numbers
2008-02-06 zzz
* build.xml: Add some apps to javadoc
* checklist.txt: Add some things
* news.xml: make links relative
* runplain.sh: Add some comments
* wrapper.config: Add some comments
2008-02-05 Complication
* Change the dates too (sorry for such forgetfulness!)
2008-02-04 Complication
* Also use the new key for checking, and add it into news.xml
2008-02-04 Complication
* Added my release signing key into TrustedUpdate.java
2008-01-31 zzz
* NewsFetcher: Change fetch failed from error to warning
* installer: Fix URL and "email"
* checklist.txt: New release checklist
2008-01-29 zzz
* Addressbook: Change default subscription
* ConfigUpdateHandler: Change default news URL
* initialNews.xml: Update version to .31
* news.xml: More updates
* hosts.txt: Add i2p-projekt.i2p
* readme.html: More URL updates
* SusiDNS: Change references to default subscription
2008-01-28 zzz
* news.xml: Updates, still preliminary
* ReseedHandler: Change default URL
* i2ptunnel.config: Change default outproxies
* readme.html: Change *.i2p.net URLs
* help.jsp: Change *.i2p.net URLs
* eepsite_index.html: Change stats.i2p addressbook subscription URL
* hosts.txt: Add krabs.i2p, true.i2p, www.i2p2.i2p
* 2008-01-28 0.6.1.30-20 converted from CVS to MTN
2008-01-08 zzz
* addressbook: Limit size of subscribed hosts.txt,
don't save old etag or last-modified data
* EepGet: Add some logging,
enforce size limits even when size not in returned header,
don't return old etag or last-modified data,
don't call transferFailed listener more than once
* Sign my update signing key
* NewsFetcher: add last-modified support, reduce number of retries
* Error pages: add icon and logo,
clarify 'destination not found' and 'proxy not found' pages
2008-01-07 zzz
* profiles.jsp formatting cleanup
* NTCP: Reduce max idle time from 60m to 20m
* NTCP: Fix idle time on connections with zero messages,
correctly drop these connections
2008-01-03 zzz
* addressbook: Do basic validation of hostnames and destkeys
* susidns: Add support for the private addressbook,
update the text and links somewhat
2008-01-02 zzz
* Add stats.i2p to the jump list
* Impose 20MB limit on POSTs and catch OOMs in POST
* eepsite_index.html: add stats.i2p services
* addressbook: log source of new keys; disallow dests > 516 bytes
* addressbook: convert hostnames to lower case to prevent duplicates
* susidns: generalize references to orion
2007-12-29 zzz
* Tweak IRC inbound PONG filtering to fix xchat/BitchX lagometers
* Allow commas in router.trustedUpdateKeys and router.updateURL again
* Change default news host from dev.i2p.net to dev.i2p
* Change jetty timeout from 30 to 60 sec (thanks sponge!)
2007-12-28 zzz
* Add zzz's update signing key
2007-12-26 Complication
* Improve reseed handler (less repetitive code,
avoid reporting errors when less than 10% of fetches fail)
2007-12-26 Complication
* Escape both CR, LF and CR LF line breaks in Router.saveConfig()
and unescape them in DataHelper.loadProps() to support
saving and loading config properties with line breaks
* Change the update URLs textbox into a textarea like keys have,
so different URLs go on different lines
* Modify TrustedUpdate to provide a method which supplies a key list
delimited with CR LF line breaks
* Modify DEFAULT_UPDATE_URL to supply a default URL list
delimited with CR LF line breaks
* Modify selectUpdateURL() to handle URL lists
delimited by any kind of line breaks
* Start saving trusted update keys
* Improve formatting on configupdate.jsp
2007-12-22 zzz
* Add support for multiple update URLs
* Change default for update to use i2p proxy,
add several URLs as defaults
* Enable trusted key form on configupdate.jsp
* Clarify the 'destination not found' error page
2007-12-16 zzz
* i2psnark: remove anonymitytracker from default list
2007-12-10 zzz
* Fix NPE in CLI TrustedUpdate keygen
2007-12-02 Complication
* Commit SAM v2 patch from mkvore (thank you!)
* Minor reformatting to preserve consistent whitespace
in old SAM classes (new classes unaltered)
2007-12-01 Complication
* Separate the checks "does Jetty .zip file need downloading"
and "does Jetty .zip file need extracting" in the Jetty buildfile.
First download (unless already done), then extract (unless done).
2007-11-26 zzz
* i2psnark: add timeout for receive inactivity
2007-11-24 zzz
* i2psnark: increase streaming lib write timeout to 240 sec and change
timeout action from "ping" to "disconect", as the fix in .30 to
honor options on outbound connections led to hung outbound connections
(bitfield never transmitted, connection never dropped)
2007-11-06 jrandom
* add i2host.i2p to the jump list
2007-10-11 zzz
* IRC Proxy: Fix several possible anonymity holes:
- Block CTCP in NOTICE messages
- Block CTCP anywhere in PRIVMSG and NOTICE, not just at first character
- Check for lower case commands
(Thanks sponge!)
2007-10-07 jrandom
* back out the NTCP backlog pushback, as it could be used to mount an
active anonymity attack.
* 2007-10-07 0.6.1.30 released
2007-10-07 Complication
* Fix an issue in EepGet whereby sending of "etag" and "lastModified" headers
broke retrying.
2007-09-27 zzz
* Implement pushback of NTCP transport backlog to the outbound tunnel selection code
* Clean up the NTCP and UDP tables on peers.jsp to be consistent,
fix some of the sorting
2007-09-22 zzz
* Send messages for the same destination out the same outbound
tunnel to reduce out-of-order delivery.
2007-09-19 zzz
* i2psnark: Fix broken multifile torrent Delete;
cleanup Storage resources in AddTorrent;
don't autostart torrent after Create
2007-09-18 zzz
* eepsite_index.html: Add links to trevorreznik address book
* streaming lib: Fix SocketManagerFactory to honor options on outbound connections
* streaming lib: Fix setDefaultOptions() when called with a ConnectionOptions parameter
* i2psnark: Don't make outbound connections to already-connected peers
* i2psnark: Debug logging cleanup
2007-09-14 zzz
* eepget: Increase header timeout to 45s
* HTTP proxy: Return a better error message for localhost requests
* tunnels: Fix PooledTunnelCreatorConfig memory leak
2007-09-09 zzz
* eepget: Add support for Last-Modified and If-Modified-Since
* addressbook: Finish incomplete support for Last-Modified
2007-09-08 zzz
* eepget: Copy over SocketTimeout.java file from syndie
2007-09-07 jrandom
* eepget: Merge timeout support from syndie
* 2007-08-23 0.6.1.29 released

222
hosts.txt
View File

@@ -1,212 +1,3 @@
; TC's hosts.txt guaranteed freshness
; $Id: hosts.txt,v 1.169 2006-12-16 17:31:07 jrandom Exp $
; changelog:
; (1.191) added trac.i2p
; (1.190) added archive.syndie.i2p
; (1.189) added mtn.i2p
; (1.188) added downloads.legion.i2p, politguy.i2p, ninja.i2p
; (1.187) added hidden.i2p, bk1k.i2p, antipiracyagency.i2p
; (1.186) added decadence.i2p, freedomarchives.i2p, closedshop.i2p
; (1.185) added TheBreton.i2p adab.i2p awup.i2p china.i2p davidkra.i2p
; comwiz.i2p dust.i2p eepsites.i2p jmg.i2p kuroneko.i2p
; mywastedlife.i2p site.games.i2p squid2.i2p striker.i2p
; tracker.awup.i2p zzz.i2p
; (1.184) added sion.i2p, betaguru.i2p jnymo.i2p always.i2p gonzo2000.i2p
; flipkick.i2p mindisl0st.i2p torapa.i2p wahoo.i2p badfish.i2p
; slack.i2p bobcat.i2p pycache.awup.i2p lp.i2p amazone.i2p
; inproxy.tino.i2p kohaar.i2p
; (1.183) added ttc.i2p
; (1.182) added tracker-fr.i2p
; (1.181) added syncline.i2p, cerebrum.i2p, news.underscore.i2p,
; onionforum.i2p, frostmirror.i2p, ptm.i2p, gloinsblog.i2p
; underscore.i2p, mac7.i2p, wiht.i2p, jazzy.i2p, trwcln.i2p
; (1.180) added tino.i2p and fproxy.tino.i2p
; (1.179) added glog.i2p
; (1.178) added syndie.i2p and syndiemedia.i2p
; (1.177) added irc.freshcoffee.i2p
; (1.176) added surrender.adab.i2p
; (1.175) added terror.i2p
; (1.174) added irc.arcturus.i2p
; (1.173) added tracker.postman.i2p, hq.postman.i2p
; (1.172) added i2p-bt.postman.i2p
; (1.171) added luckypunk.i2p
; (1.170) added bash.i2p, stats.i2p
; (1.169) added archive.i2p, www.fr.i2p, romster.i2p, marshmallow.i2p, openforums.i2p
; (1.168) removed duplicate manveru.i2p
; (1.167) added bittorrent.i2p
; (1.166) added elf.i2p, de-ebooks.i2p, i2pchan.i2p, longhorn.i2p
; (1.165) added amobius.i2p
; (1.164) added google.i2p
; (1.163) added mrplod.i2p
; (1.162) added sirup.i2p
; (1.161) added connelly.i2p
; (1.160) added wspucktracker.i2p
; (1.159) added 55cancri.i2p
; (1.158) added tracker.fr.i2p
; (1.157) added v2mail.i2p, complication.i2p
; (1.156) added lazyguy.i2p
; (1.155) added confessions.i2p, rsync.thetower.i2p, redzara.i2p, gaytorrents.i2p
; (1.154) added arkan.i2p, search.i2p, floureszination.i2p, antipiratbyran.i2p
; asylum.i2p, templar.i2p
; (1.153) added feedspace.i2p
; (1.152) added wiki.fr.i2p
; (1.151) added septu.i2p
; (1.150) added music.i2p, rotten.i2p, wintermute.i2p, kaji2.i2p, aspnet.i2p,
; gaming.i2p, nntp.i2p
; (1.149) added cowsay.i2p
; (1.148) added irc.postman.i2p
; (1.147) added subrosa.i2p
; (1.146) added moxonom.i2p
; (1.145) added sex0r.i2p flock.i2p cneal.i2p www.nntp.i2p wallsgetbombed.i2p
; thedarkside.i2p legion.i2p manveru.i2p books.manveru.i2p bt.i2p
; (1.144) added riaa.i2p
; (1.143) added mpaa.i2p
; (1.142) added pants.i2p
; (1.141) added irc.carambar.i2p
; (1.140) added general.i2p
; (1.139) added smeghead.i2p
; (1.138) added nntp.fr.i2p
; (1.137) added deadgod.i2p
; (1.136) added manveru.i2p
; (1.135) added fr.i2p
; (1.134) added imhotep.i2p
; (1.133) added jrandom.dev.i2p (ed. note: yes, i am me)
; (1.132) added ttp.i2p
; (1.131) added freenet.eco.i2p, tracker.i2p, photo.i2p
; (1.130) added hopekiller.i2p, microsoft.i2p, jhor.i2p, badtoys.i2p
; (1.129) added mindspore.i2p
; (1.128) added irc.ircbnc.i2p
; (1.127) added dvdr-core.i2p
; (1.126) added j.i2p
; (1.125) added bl.i2p
; (1.124) removed jap.eco.i2p and bt1.eco.i2p (obsolete)
; (1.123) added chat.i2p
; (1.122) added phonebooth.i2p
; (1.121) added up.i2p
; (1.120) added dm.i2p
; (1.119) added piespy.i2p
; (1.118) added sciencebooks.i2p
; (1.117) added forum.fr.i2p, fedo.i2p, and pastebin.i2p
; (1.116) added frosk.i2p
; (1.115) added theland.i2p
; (1.114) added dox.i2p
; (1.113) added amiga.i2p
; (1.112) added frooze.i2p
; (1.111) aliased gott.i2p as jrandom.i2p (ed. note: no, i am not gott)
; (1.110) added sonax.i2p
; (1.109) added 1.fcp.freenet.i2p and copied fcp.i2p to 2.fcp.freenet.i2p
; (1.108) added asciiwhite.i2p
; (1.107) added fcp.i2p
; (1.106) added greenflog.i2p
; (1.105) added bdl.i2p
; (1.104) added bacardi.i2p and guttersnipe.i2p
; (1.103) added evil.i2p
; (1.102) added bsdm.i2p
; (1.101) added eschaton.i2p
; (1.100) added blog.curiosity.i2p
; (1.99) added slacker.i2p
; (1.98) added ses.i2p and pdforge.i2p
; (1.97) added orion.i2p and protokol.i2p
; (1.96) added blog.polecat.i2p
; (1.95) added ciaran.i2p
; (1.94) added polecat.i2p
; (1.93) added susi.i2p
; (1.92) removed duplicate beyond.i2p, added edge.i2p
; (1.91) added shiftfox.i2p
; (1.90) added underground.i2p
; (1.89) renamed newsbytetest.i2p to newsbyte.i2p
; (1.88) added newsbytetest.i2p
; (1.87) updated curiosity.i2p (via signed email)
; (1.86) added blueheron.i2p
; (1.85) updated files.i2p (after verifying ident)
; (1.84) added utansans.i2p
; (1.83) added irc.orz.i2p
; (1.82) added nano.i2p
; (1.81) added ragnarok.i2p
; (1.80) added marcos.i2p
; (1.79) updated beyond.i2p's key
; (1.78) added b.i2p
; (1.77) added tinyurl.i2p
; (1.76) added detonate.i2p
; (1.75) added identiguy.i2p
; (1.74) added jabber-2.i2p
; (1.73) added jake.i2p
; (1.72) added anonymnet.i2p sasquotch.i2p orz.i2p microbleu.i2p {www,smtp,pop3}.postman.i2p
; (1.71) added curiosity.i2p
; (1.70) added freeciv.nightblade.i2p
; (1.69) added xolotl.i2p
; (1.68) added modulus.i2p
; (1.67) added eepdot.i2p
; (1.66) removed datagram_test.i2p
; (1.65) added socks1.tor.i2p
; (1.64) added sugadude.i2p
; (1.63) added files.i2p
; (1.62) added beyond.i2p
; (1.61) added gott.i2p
; (1.60) added linuxagent.i2p
; (1.59) added www.i2p, dev.i2p, and cvs.i2p, removed i2pcvs.i2p
; (1.58) updated lucky.i2p (after not checking ID, but, c'mon...)
; (1.57) added firerabbit.i2p
; (1.56) added datagram_test.i2p
; (1.55) updated ardvark.i2p (after checking ID)
; (1.54) added files.nickster.i2p
; (1.53) added brittanyworld.i2p
; (1.52) added stasher.i2p
; (1.51) changed quadn.i2p to library.i2p
; (1.50) added freshcoffee.i2p
; (1.49) added ems.i2p
; (1.48) added ooo.i2p
; (1.47) added fproxy2.i2p
; (1.46) removed hypercubus.i2p
; (1.45) added thetower.i2p
; (1.44) added fproxy.i2p and mrflibble.i2p
; (1.43) added files.hypercubus.i2p
; (1.42) added www1.squid.i2p
; (1.41) added quadn.i2p
; (1.40) added nickster2.i2p and irc.nickster.i2p (pointing at IIP)
; (1.39) added jdot.i2p
; (1.38) added forum.i2p
; (1.36) added ferret.i2p
; (1.36) added anonynanny.i2p
; (1.35) added hypercubus.i2p
; (1.34) added ogg.baffled.i2p
; (1.33) added morph.i2p
; (1.32) added nickster.i2p
; (1.31) added mush.zeit.i2p (i2p's first eepMUSH)
; (1.30) added xilog.i2p
; (1.29) added lucky.i2p, removed lp.i2p
; (1.28) added sungo.i2p
; (1.27) added jar.i2p
; (1.26) added tor-www-proxy.i2p (WWW through tor by human - won't be up 24/7!)
; (1.25) added ugha.i2p
; (1.24) added reefer.i2p
; (1.23) added nic.i2p
; (1.22) added www.janonymous.i2p
; (1.21) added bluebeam.i2p
; (1.20) added echo.baffled.i2p (which runs mihi's echo server - telnet and get replies)
; (1.19) added irc.baffled.i2p (which is hooked up with irc.duck.i2p over i2p)
; (1.18) added www.aum.i2p, nntp.baffled.i2p, www.baffled.i2p, and ardvark.i2p
; (1.17) added gernika's eepsite
; (1.16) added duck's scp and hosting server
; (1.15) added eco's beta i2psnark server
; (1.14) added duck's pgp keyserver
; (1.13) added human's eepsite, the mail servers, and luckypunk's eepsite
; (1.12) added fillament's chessd server (FICS based clients or telnet to it)
; (1.11) added mp3.tc.i2p and mesh.firerabbit.i2p
; (1.10) added aum's mp3 and ogg streams
; (1.9) added the FCP and HTTP keys for a private entropy node, as well as nm's eepsite
; (1.8) updated nightblade's eepsite (after confirming ident w/ trent on iip)
; (1.7) added aum's eepsite
; (1.6) added fillament's flog/plog and eco's eepsite
; (1.5) added duck's irc
; (1.4) added eco's JAP tunnel
; (1.3) added duck's eepsite
; (1.2) fixed duck's subdomain names
; (1.1) added nntp, jabber, squid, and i2pcvs (and imported into i2p's cvs for distribution)
; (1.0) added dyad.i2p and nightblade.i2p
; (0.5) added bozo.i2p
; (0.0) added tc.i2p
;
tc.i2p=3RPLOkQGlq8anNyNWhjbMyHxpAvUyUJKbiUejI80DnPR59T3blc7-XrBhQ2iPbf-BRAR~v1j34Kpba1eDyhPk2gevsE6ULO1irarJ3~C9WcQH2wAbNiVwfWqbh6onQ~YmkSpGNwGHD6ytwbvTyXeBJcS8e6gmfNN-sYLn1aQu8UqWB3D6BmTfLtyS3eqWVk66Nrzmwy8E1Hvq5z~1lukYb~cyiDO1oZHAOLyUQtd9eN16yJY~2SRG8LiscpPMl9nSJUr6fmXMUubW-M7QGFH82Om-735PJUk6WMy1Hi9Vgh4Pxhdl7gfqGRWioFABdhcypb7p1Ca77p73uabLDFK-SjIYmdj7TwSdbNa6PCmzEvCEW~IZeZmnZC5B6pK30AdmD9vc641wUGce9xTJVfNRupf5L7pSsVIISix6FkKQk-FTW2RsZKLbuMCYMaPzLEx5gzODEqtI6Jf2teMd5xCz51RPayDJl~lJ-W0IWYfosnjM~KxYaqc4agviBuF5ZWeAAAA
dyad.i2p=W~JFpqSH8uopylox2V5hMbpcHSsb-dJkSKvdJ1vj~KQcUFJWXFyfbetBAukcGH5S559aK9oslU0qbVoMDlJITVC4OXfXSnVbJBP1IhsK8SvjSYicjmIi2fA~k4HvSh9Wxu~bg8yo~jgfHA8tjYppK9QKc56BpkJb~hx0nNGy4Ny9eW~6A5AwAmHvwdt5NqcREYRMjRd63dMGm8BcEe-6FbOyMo3dnIFcETWAe8TCeoMxm~S1n~6Jlinw3ETxv-L6lQkhFFWnC5zyzQ~4JhVxxT3taTMYXg8td4CBGmrS078jcjW63rlSiQgZBlYfN3iEYmurhuIEV9NXRcmnMrBOQUAoXPpVuRIxJbaQNDL71FO2iv424n4YjKs84suAho34GGQKq7WoL5V5KQgihfcl0f~xne-qP3FtpoPFeyA9x-sA2JWDAsxoZlfvgkiP5eyOn23prT9TJK47HCVilHSV11uTVaC4Jc5YsjoBCZadWbgQnMCKlZ4jk-bLE1PSWLg7AAAA
nightblade.i2p=nyErwSseXbsojcWtNkDyUul0YULtqr6qyWSzIp639Ygpe8juCdgPMLURVXcmlCvo~QPoHg6zt53KpgpGvB1-Wv2SGvc2Mvs~o8USw3ius8fP1URphqcBbulK8Ci0bgknt0kD0AfxqfMz-p~xk1QEMxq2kZEoB3oyIIFnQlpb2ByS74Lx8iKzXTrwWk19I3Dvu4nIq8CBDDwu3lYoCD2kC-jT5pjgglverGPEGN4o55LYVTtfSg4gAJFZeaE4KjBR5P1z7cca6UDjGMWfR0iCa8P3qpkY2ODYpk~8w2xgBbgDq-8Hzik~uraHc598ccS8QpwB0f0Jw~2PZcTjOPdZ-239U6p3tESXa7FXzRBCujv4Bx6CVFRhCmBHpyFnCD-MugZ~vR6XFSS2XBsCT~duXKq94HH2n1iAWslG4Vu44ut1JVhDPFzp~Dk7wujB0tCo2HXH2icRQxOWe37foU4LZSJ4oMpFDACBzwSfcZdIPsVRxGttKQx4yzgffR1Q~Jl7AAAA
@@ -376,7 +167,6 @@ irc.carambar.i2p=xfMseaHQgLA-MjJTKZoe8fL8cfjOhJBe1ii23jfdInJoioDTNRLJE4EnMxdda4Z
pants.i2p=Nawyl6EPP30naqz3VwiLiThON4i78Peras6RCtMMUdt62vAND1mQGejJaO--eJfICziDMVhGbrtvAOZzlPBxVhswxENkFFawNf6yDVsdJgJgdtg9i7KUU120IgGS5wABdv5w0sAIn19lu7oZT~Yl-MI6um~Wvg6Dc3SPbHSCgNBMXzuUN1yNGkYdM6xOOkqCEl3H~NujG1gqac8EY5Q9edh0DSMpGXP6vCqVbw6C6uO5InfL5G3BCB4mgq-MooflyN5RL3qELIUnwN76QcOIcHhWbNhbMUzFnwra9g7044GnFGgZZHgkd8iQ25d-en87UHnwLVAxzg7nVj7XTEM-l1CoeQCbPtqZNjn--PMPlLL8b4r0eR6SMV63EhZQzm6Z35C3nhKZOKoeCPPrObi6dgQWk1qnisOUu5isXYA4X~e2xhSrDEXw3UTK71Tpxc6VIw5nBCAD~HLGlOCZGWIKsmUvsgjFBsKNwfl5dhnDCXFWqKaw8ZKo7zpAyXfc4A1EAAAA
mpaa.i2p=99SlYfaoMM9xHU8Pl9Pdi77YxuPfULgOoNED86rEH~JxLpsLB8g6stATdoGZye3fTVxnuFIrnPBLR6UBPyFS-FSGr2ZfXcknOdNyk~tes5AxaRvSzuqFsJiOpLvsnOLAN~D0Mu7ZmZJybBRSQhqZiVVczQBM6kgh73EyX6WYwLL3RtWu6zoggVuYZbqPhVpGxun22zI1ZGhTaLZtI8XqgHeeQbSv1dYjAxJxGlWzFb88mVvvOt-X-QjT0G1jNa-wjRutRHja-bIXDRpc1-4cffmbXw2IksSpwZ7BPfLrMKrlvzZxnjjAqiatyPGHR5tkczaD~HCI3p5p8JzIMAgfVpfx6NSHLX5n6Ymm~hQCnT60iwjFAP8AB1LXrLeLaIR~V3ryCs14f9psjleTMCrwPn34h38QWWnxX85cQ5n~P-vvz-wu8uksKvCN2fvHDNEhnIFdy~AYAywVn-UjzLwR1~SHemmxhQoGpwm4YWxnAgrHRHtYX3wzx8aNBMogs5EsAAAA
riaa.i2p=cpnfxy9veluR3ZnwYeprHrJt7B359PymL0OEUonqKOTVvemHU9h-WBObN0xgfOajDTWhOskbZ~danOnSJGXmsRI1VrxhjCpJ4ruNcKwILjLv9s7Xa7aWp9MeTNdLJTtTIH9n84HMPd3pG6zHncwI54DUwZTqPkvg4k1u~ZU7fmyT0e5xmog1KBnRoE-ZYSkIAM~H-O-hKtrozkC~FHnMsxq14U6YSwL6e6dQmAXHjcF7u75bYNRbCQJfl1k1XWLVtTimbL3TuNR-6vDX0CyRxt~ma~kKBX4qYLX3SZk7uoX9LX0rFTIAk~1zhGm4yvr~YvXKm6dCJeIgaV1hfQyzqU6iuvgx-Pw9bU5SZiY97JezC0Uj6D5r0~nR1zfD4ULy7slfQsI9NipPtdpHIitcbzXjdwmAfSADNt-dy2MFn-6WqxHG9YUaN4cVUp-tquEqf3ppQ9ynbDABDhcu3ZJ85NccpTCcNRkCUobj9fUWls0tw20dxRLkHmXY-U7r64TfAAAA
sex0r.i2p=FXBJquP-C0O1YWyd3wa0FiUgFRn3qN4jADGRTlplVD0LPHepWTPZQB~q29Oj30Q439Vd~KBMVTBp64OI04arwH~xbWPPpKRHhWtqtNfYbSk8UQ2JO~eoKuUlkCvF2H7sqLjZuRbzXz9M4hmUbTEnYzbi6udR56OoI4HVe86ixD9of6PuXGli2OnEKCjXgqX6tp9O0gLrEjeqepvyHHwDhyTYmmSaAXaZsjNgRHtKxnSimnYHij5zXcwiGcSmwZpG3~%20CJiiETf59tA32Mcf5TcRztPRHZNfYfTWN~1DdlU1Nv5x3RJptecJFgkWRIuRXd7DDNCxyibIx9kGBExs11wJl1XOWUtVh5PYVcYV5KSy1~Zz-B5Hovb8AFBjam0r2P0zoKB0-7mDhjhHloeOOyV2txVoZQbgpGNXPlFmrsxtpbDaCB0FBqGw2tPLksgqKJpDmNxE3usNMMy8gv2NtZ92fuHcwr95YwwgoDrePB6-AqywWjYlffyQvEdw0zqLs8AAAA
flock.i2p=W0fudCJgidi6SxrdX0YrV7k1~5fKiQsopQdSNa-2D-P7wmJE3nipFnlGY9QEiIRMOBf3K48Q406Glf2zuQLjtrmO8li8SGu9iHOAai--aidcRjVS6n2L70iYnYMK5godipzbAROt-pyHroYq1JnDptqPZGHBovDiwJcPWUIY7Qizl9AWkj3FSXvXCRnb8aeLOVFUiKKPKw~mQ7BPUFWKjmVUuJFON2kxzEBm4p~V4EUR4KGijb3-8JYnMVC4PRk5KNGGxaQ6vO2mnW2Ix0I4JRhG-KL59Tbn6reQBSCL~jiZg9~v7NJHMNZJI8Yqv-76Z1sC1Y0b0fm58J-yO-gQxBlA9CPRpA9uVsckD6wMww1B0ssYjV8oMRtljEpWvJAH3WCTZuT9~i1rbj2dG46hWvMVI9-vQviEDTGjeMagjUWxNkjxU-2LgHUCrfUKfVwqfzUFV1oDVi3MgvWasIK6zUY4LWFz0e4F8QNllJgSdMoZ6PaLZGbi4s8zaoktITA4AAAA
cneal.i2p=rOcHhSaRh8VHx-oViRwBBZM49AM3OykwAyBBMkjSlUluFtUFvVbeQDpmMk7CjqwWYFil-wrGOsQBNZw7tLz1cUlvGvAcs-Ji3W9djNPwlYxiY8OwghAFaWoiIWT3cbDuPnugNp9S5sIIvhCUwtALNDjgxSgR3wFvM3FE-Ye9dZpSophLZbUUIZtaholSjZW5yCC8rGftNr3I06Ax1B52jRm0c-niq6AWLb0wYSc3fUcZsIAeWWFfXNGcHL2X8qcslu~hfklQfL36mWgDySd3sjblt7Xg4DbvYkj5ZejnVJIGqY1ZvbOrZkO8kMEUIyqW8Tk5x8aawlfMDj2Cy2RUa1rOKhJHsTfTMB74SHnsGrYk9Cf~G-~6erIns3S085KK-oS1U9MWP9zOVtTzdtlWGjKktWu49e-xzoNbsH9flDZ6d385On~V2fl~zNqQRs-91pv9MDE63bhxroUI4NWst4mfV9zHjgk7Izt4pO5jmzh3KAF2DgCb2~BcMC-x3CM0AAAA
www.nntp.i2p=H63RoPaxWD5GTW0HoceyM0vihVal3vpfPyBbC~9yI0~i0WrCs9twJa6oP7RlhT~AIfFKiWaaZLxsKOODuvSwmuM0K4mFSAVYeCWzYeNnbLFrNn85u7cO~w03Rp5UyrxAFMNVE2Hxrgjw9ZPQGRZ8eE6GGEyx8etzkkXoknS4uDhN-qhfTEuYPiVh0Lel4H~VkdiCwepK0tBbxKeKQYtokoFnosrlGo49krkoXD2hLfxPSc-dFHqaQgQqV3XLzKAsb0NUxNMHA18Vr-WBOcB-OubqONpbWAejcB-X6rcZ9rc1b4mAtU~YeV64WESGf9GLadAKb1Z6bfy2qA~-twMMzQzNHmU5b3F0hcA2LD7kZSljZynoss6M2oWAsifewsQ8lKkgXhoyOHjU4sWRUZSxsObcLuI~HM2eWEOkIsBH3MSInC7BSRKKg7GUK3zj4M7f8muHiozOTWCvw5vevV9ay274N~JRrZVKb83oqC3hGoh8OlInMq5RgyyEmuuqcT-RAAAA
@@ -504,4 +294,14 @@ ninja.i2p=XhyN8MgL6DwWE98g2DJlDLHy~02g58IF14LTb472cmSLRj~cHv7wyi1mxy21vtf12oPWRq
mtn.i2p=RqXC4xbFK6t3g2wk9SO4RjY7mj1c0DmtMra5c1Md8t-DcNPSjQFmqT97pcZ5IR1JDKqyCO7RI~aATTTMPQexoEeqK9-6Poeh2RA1C81FzcA9sHvjLeg3eB1Cju-sE-IDeFntEvCC4w7wWnpmLzCfdXK7OjSK1wYc6OkqPOLVDEy-N-4UUPlZFWWUghpjBGXGayXz6JRKtoMIwhFQaiKdRvAs32ozM9RM0NWzrCaRLZBIQ6Gg1Ys1wF0-oBJgC4T4CN6SxJNaz9Dfw4GNtPyD6lq3S1osY1ccflm3itvUt3JC1J9ypoXzylBE5MuS-LTgbgbMdMFty07AoWB~EY8TwW8EQQO07GSzB7hm53u0iCEH44GexhKHtQP-hYbIr3mklo89BvfWIRGMTwUkAzYojzC-vOyIh16LWrQQhGbLvByKQSdWk9nInm3GEfqRVtSpuqd4m6iHzrBDZ3fvKjbuywot3hDNHitOHOedmBNA8neCzLkod8b0Z4xx~qRIEObxAAAA
archive.syndie.i2p=iXX0DadZTJQpPr1to0OmQ4xokHgx1HYd5ec7~zIjQ80W~p4kRCYJmEzibH2Kn59Gi04SAXeA2O9i3bNqfGCQjsbz7UcjPGrW6-UrckXVXW67Moxp7QWY6i-aKuVYM3bqYxUL2mWvcDzJ8D0ecMpvasxhxwXpdFn2J6CGboMxeGV8R3hwwlNYbYoKgHr74qEJaIZpm1FrRWvNHV5cMv363iWnPy72XspQefk79-VOjPsxfummosU7gqlxl5teyiGKNzMs3G6iJyfVHO8IlKtdn~P~ET9p7zWlTPgV8NTyCVB-Wn5S3JMkMGOFZR7wSlxSwGFpTFQKc7mxVTtLZ5nWcV2OhvOIxRZ31RvGJZyVs562RC5aMfyqcM5IHQiZVlmkhzJKIy9VDw8tKayQtRM-xeN5k6Qr7iMmYIRORwuAODkYApoMD9a0eJ6ZYOSgBMOCSvYcwfT8axRY~GabiHm0QC82mo-nDgrUypGKtOPMI9MIqMTsb8Yl-UGWn6twBAIzAAAA
trac.i2p=OBnF9NtkEsPij2F-lp3bWDVrJsPQQPdq6adlpq0N4BY1XRjtDBZl~EpDdk7roq49~ptKAQG2cNUeBEKIIrdlZhJio5pMwUl6YinizzkNTFfZipB5OKoB7PBulxkw-N9mKMhS1btd9ajcV8tiP3xiv7VSlgiDwbdKg1fmkvNrVrJnzkN3-ey2kebYnbh7jjU2gPFUl~CwSEkIi6AK9EfqmFR-DUVohyygqAY~fi4EMeTVXGUqftXSNFYUwpRJgFrWRPTurtZnJK5403q67oEk0eWrPIZ8ytJWSBfffAXL3ts~0O1FZeKXUccsAl33j70~lklSolNVLJ40y-6X5ZLWajmX0ONU3j0qI5A~7fgNgsg-vKypPDuzl8ug-D~BmhqdAf0sRYmziDVwTgU~WRB6IzhhXFR6CbwrGXdgOGg2qNT1eOnMwGo3SMMJ7kK88VC5LdYg2dyiyjZATuvT92QdZglrVQIeBqAehcFjOBuycC1ED3AOak8D9Xplj7V6hN-HAAAA
trevorreznik.i2p=FxoG5dx6WuF8gu0Fc4ItB61hd8dBZ0L6FjkvoA-kQrC0DcY5YUqKBUmrcxzKhKo4nLyg0jRV-RSNUuWsali44dmpHQ6wuFjCGTr5zMk0NoVUpBsBNtHLEQWxROnuQFlQAq6x~eVdU5bAvnNFd-6RXDJ86Br9bf5YG4PHmZPon7ld3t1kAvPaZepITKlIq5iXy3va-pzAMFEIhDtLMzFjGhLWMg9m-8tkx4577WvzUWbSAUdxKkxwjecIzbTDTQsZld~t5MkaMmn5UpNX6Gh3iDUPWHXOjn4I8MIELiSaeRdpHDgua3mo~p8oO0QvWBgn~jQ8yr6nz7vMAdoRtOwPlUqHCCM1BsPVcN9a92rPpTFBk0BXikjJJrkDDIaFjJnKmRAsEUoa-eHaPV~RS0QPrfuzlp0XjBzQcAQjNIw6hO4xqJujSs8SdObMpQAqCR5Sc5NzOvTr5eAzCIz0gmQnKrA1RJVOebKDERM~qQ6rFrdVDkjLEJd6SyjUr-TdIrayAAAA
i2host.i2p=FkX89~FOWc2HjTeVerud7hzZCtQNDKqEvMeJiDEnSzneA44hhDEDSbjiDuEWOCPwvgCwrzMg9o3apHXosNMnRVTYlYIJWb1~fgRnzkHIJnz2yrojLcTElTLMgQSzHdV04ock3oPHjw8r2j73hnTiq5u3HhexT0D-IK02S0GUd9cPcP2YnWlNMnGuA-J6s7VHUd5mUhBO3LeOcOusBUOjsbt79bwBZYsnnVV~JRSVzHPd8kYbRMEjDuyaIJHEr2pkwwtrk~BqLeZ5UCbbVob1-733FtOfQXjKTpFPK~IlHDM7ItgXt77U5KZHkZ54WQYJNCE6HlE7LhFB79cqjgvxXTfvyjoqZVJ1lq1yFS8GtLcnurJLkN5BleCEDJEK3D7kCymCpngW9wlKjakEc85ZculU65neqIpqIk6noir6e1vseeUZKxBM3k6AYkLoFYSh98PpENjTHUdaNTl1kQA2Mmi9zobGS0gn0~RWHFord19TC5ReBtOFWkseksHp-5-nAAAA
true.i2p=Jeb1Ctlh55wWezbA~sCxYQsreDPS~qFJ6DeNMPl7~Kx0w1Odh8YE3QKrZS7WlNqeoRNJLyPgf7h19Tosb-ATZOPDH7B4pQvI4CdlTv-Uimq4dI71PRRZQr3mCBihW~WtVReDOO3JiDf1Bx225xhTmWp0KYo5AM91EW0TcHi8immHBFB9jcjekPoU~zlVAqy5S07LnS7f7rWtC7kno983Dyi9arWDPmnnzu2QD4mMrH0EkuuoBqwUi1HBUNhTn~lL8KqfSpg9j9q-eqd~eixF3nOlsrxMFuWVV1HOUtyMUTRGEX4i4IDPWmRQeFZ0gmfeBYdad~nG1X7uBVeeEtGSrggnegXoSE4oaIuONNXYORsevZn8UahC~kkNWg1wPQtr57TirhLirkF2qHUuwAqe5G00PIhC0-J8K5Ye0QDd5a1coQT87kBgcqLcbSR1oGIjxv2Ma6970Fv65a2a~YKqZZbuGof5-5-7X48SVhOigmo2c-COyt2rXoQlGQpBWtDsAAAA
krabs.i2p=k6qIwzff6s1RiRQQy9O6cliBTfHffKZ2F~pVG8nmCqMxEpPnywynFa9XVS6VBbhxGRAMG~PIb2IaFRYS5GFdM3fnnJ~Cn2AbN-qsqbl6cXExj5Fy9Cd-aPR44XW0NE9qjFPiN~6JUOg0fitF65RmsMrFvHq9LM2zOFxOfnPKVsBJGRpjhp6EPRNrkXvzQTw7x6~kqUJ-VGW0avjrz4EmgT6Wias5z0EPioneKOhG-1NepL8HqEv9ryGt31~kmI1-B0cS8v1riaXH0rZWjJ0VvUFEoJ3sHCir4vsnSf1YQIKMUO~zKlgTVZBsw8P2ILFFihs0g9KMIWVjJqqo0PzCM1O-LW90hirn~Ryh4zOZI-orIiV9Oqu96Fj2bvBYSka11TY7erLOCk64tc5NwxvlJQ3F-lk0ZFGvYuU~l45mi0khFLnDnzhDFtcY6YNLRG8hmv9IR2MrG9TJFfSwXdx11LI-57tkRi9Jw4s8OjLijNNDOJX~rVgwZVVIEQcOhGxkAAAA
www.i2p2.i2p=-KR6qyfPWXoN~F3UzzYSMIsaRy4udcRkHu2Dx9syXSzUQXQdi2Af1TV2UMH3PpPuNu-GwrqihwmLSkPFg4fv4yQQY3E10VeQVuI67dn5vlan3NGMsjqxoXTSHHt7C3nX3szXK90JSoO~tRMDl1xyqtKm94-RpIyNcLXofd0H6b02683CQIjb-7JiCpDD0zharm6SU54rhdisIUVXpi1xYgg2pKVpssL~KCp7RAGzpt2rSgz~RHFsecqGBeFwJdiko-6CYW~tcBcigM8ea57LK7JjCFVhOoYTqgk95AG04-hfehnmBtuAFHWklFyFh88x6mS9sbVPvi-am4La0G0jvUJw9a3wQ67jMr6KWQ~w~bFe~FDqoZqVXl8t88qHPIvXelvWw2Y8EMSF5PJhWw~AZfoWOA5VQVYvcmGzZIEKtFGE7bgQf3rFtJ2FAtig9XXBsoLisHbJgeVb29Ew5E7bkwxvEe9NYkIqvrKvUAt1i55we0Nkt6xlEdhBqg6xXOyIAAAA
i2p-projekt.i2p=8ZAW~KzGFMUEj0pdchy6GQOOZbuzbqpWtiApEj8LHy2~O~58XKxRrA43cA23a9oDpNZDqWhRWEtehSnX5NoCwJcXWWdO1ksKEUim6cQLP-VpQyuZTIIqwSADwgoe6ikxZG0NGvy5FijgxF4EW9zg39nhUNKRejYNHhOBZKIX38qYyXoB8XCVJybKg89aMMPsCT884F0CLBKbHeYhpYGmhE4YW~aV21c5pebivvxeJPWuTBAOmYxAIgJE3fFU-fucQn9YyGUFa8F3t-0Vco-9qVNSEWfgrdXOdKT6orr3sfssiKo3ybRWdTpxycZ6wB4qHWgTSU5A-gOA3ACTCMZBsASN3W5cz6GRZCspQ0HNu~R~nJ8V06Mmw~iVYOu5lDvipmG6-dJky6XRxCedczxMM1GWFoieQ8Ysfuxq-j8keEtaYmyUQme6TcviCEvQsxyVirr~dTC-F8aZ~y2AlG5IJz5KD02nO6TRkI2fgjHhv9OZ9nskh-I2jxAzFP6Is1kyAAAA
nickyb.i2p=9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA
tracker.welterde.i2p=BGKmlDOoH3RzFbPRfRpZV2FjpVj8~3moFftw5-dZfDf2070TOe8Tf2~DAVeaM6ZRLdmFEt~9wyFL8YMLMoLoiwGEH6IGW6rc45tstN68KsBDWZqkTohV1q9XFgK9JnCwE~Oi89xLBHsLMTHOabowWM6dkC8nI6QqJC2JODqLPIRfOVrDdkjLwtCrsckzLybNdFmgfoqF05UITDyczPsFVaHtpF1sRggOVmdvCM66otyonlzNcJbn59PA-R808vUrCPMGU~O9Wys0i-NoqtIbtWfOKnjCRFMNw5ex4n9m5Sxm9e20UkpKG6qzEuvKZWi8vTLe1NW~CBrj~vG7I3Ok4wybUFflBFOaBabxYJLlx4xTE1zJIVxlsekmAjckB4v-cQwulFeikR4LxPQ6mCQknW2HZ4JQIq6hL9AMabxjOlYnzh7kjOfRGkck8YgeozcyTvcDUcUsOuSTk06L4kdrv8h2Cozjbloi5zl6KTbj5ZTciKCxi73Pn9grICn-HQqEAAAA
perv.i2p=HazSt3kSqVjpMO9Ol9HPjXCfzTLurOPjSeN47UxMLLs4lm5SJJHP-p3vA4sTfxrR3z7Cqq5Nd0t1gog~bV0PCbnKNsTiF~pSPBIFXOPVe5RuX7keDRJ-Mp5-quPIe2FFNEOz7HNkbuz6aHYN74T5Cs2VcMDEvL9Wz~oxV7FPSijD1qs1hi~f3byvSvswRkt4w7A10iJvunq43r1jOi6JwS~lAChP1q7t16sfhtWp4XEaEvfES0bIbnTsRv-aDVy0Kp4zYYPuZstit-S8GHkS7ceDRHSoid1O6V1WgogeDoTRzfxfHqQb5db5xWt4DXmnQbb7xysXub-2S3mbog-WnoawDRM5ZJDItCDuMsg0edIn5RJYkANh0Qox-JMVUZdU8tcx--DX9gONJ4cm4a-MLxY9dme~Zq4hqJJRNRvrRcA11ZuLH-ZN3aTXL70Yod-YyNPcechGrpugKEU38g5sDyj77pX~IrdaTVTFpJE6zlClRatTnl4Enhr4pQ7gWFpcAAAA
false.i2p=V5EeX1UrVanCQhE9q-Nj5UFRyQiH6b~lSO7qe8hgxGZkymrpHFZ5j5D9rVOjsogokon1bZF5NPlPdzI~d4Ap7UyqBR~90vhFxsIKednRZLdf46JgjYTZq~ct-Bi3sdpBXdg04L8i4dStE4jkdvl6NF96MfQKdt6mtYFeaXb0XhPx~04NECG5~y~mTYcMjcvrftt5uulLbT6TcGmJ0KV5Xu2UVnkN3zOaQEObIIDZT4wkz9jOqaiJzMHNJqWc4GU4ocIfwxeMkSn9qvA0Q1AXuM~z11~wgHYLVEFoN5k0O4aB8b1r1WtpZTojZ9ADThW89q~AcD981nIYnRp59cmyqBdN7X-71cBrKC7QfnCRJpbwoVrn7kePw1dCu6Bobnd4~a74abxjFeCxVzQxSTbkey6f~wJXE2JPAqfsM1EKXsdqUZQJOP0ngQu16srSpqMSxkqHzlr3US~Vn9EgMcHuDCkdctwo7stwn0UQ34sSF9sLhtmlHIGqatDhfmYEGmSiAAAA
mtn.i2p2.i2p=G6VmsrLYbdcxBq585OUcQn7wbwC7J5jfXDWWL6lPBw5iq68VxqxibraiPwwF6NM2aHV8BkqyCKYSL9fUuYWoeUc1zL~2l1DX2x~LfyItGJKDIUGImWQivXF1w7EGYMhjq4UCmPKTsnl4G86oKW8PGaaF8mzjjUKW1R7G7941my~mnbeTrhjlLgaMK-tauVodgTPIYkxfMJaq3zWuirztuUgDcXXIbkpzaA2Iben0VqbjbMJisj4fFh0EvqNkYAG54YBc26~W6SPWyBgZilXvFlcizF90Q5NkIGMMHXTq46qEYHkpQC3CoaH6PMNVDetDPmFc3QXmc68cNcj~VPh4XVsn3qiKhXuRdXggEC3RoTcxqaeassfIG5xhRdnJzGSVhYUE3At~8wI-AuRV~AglV1Q-AZTWT~9VxBzcxfI1PpfzeA-5z5T4542bh1e-RM9tzXEx5ErPCt6M~zJ2~4-tz-aBsZEhBkn0iDi8pazshg6lTl1~hCnueZBxYICqPrlBAAAA

View File

@@ -1,5 +1,5 @@
<i2p.news date="$Date: 2007-03-17 20:47:59 $">
<i2p.release version="0.6.1.29" date="2007/02/15" minVersion="0.6"
<i2p.news date="$Date: 2008-04-26 15:00:00 $">
<i2p.release version="0.6.1.33" date="2008/04/26" minVersion="0.6"
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"

View File

@@ -4,11 +4,11 @@
<info>
<appname>i2p</appname>
<appversion>0.6.1.29</appversion>
<appversion>0.6.1.33</appversion>
<authors>
<author name="I2P" email="support@i2p.net"/>
<author name="I2P" email="http://forum.i2p2.de/"/>
</authors>
<url>http://www.i2p.net</url>
<url>http://www.i2p2.de/</url>
</info>
<guiprefs width="590" height="356" resizable="yes">

0
installer/lib/launch4j/bin/ld Normal file → Executable file
View File

0
installer/lib/launch4j/bin/ld.exe Normal file → Executable file
View File

0
installer/lib/launch4j/bin/windres Normal file → Executable file
View File

0
installer/lib/launch4j/bin/windres.exe Normal file → Executable file
View File

View File

@@ -6,6 +6,7 @@ Proxy-Connection: close
<html><head>
<title>Destination key conflict</title>
<link rel="shortcut icon" href="http://localhost:7657/favicon.ico" />
<style type='text/css'>
div.warning {
margin: 0em 1em 1em 224px;
@@ -31,7 +32,7 @@ div.logo {
</head>
<body>
<div class=logo>
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
<a href="http://localhost:7657/index.jsp" title="Router Console"><img src="http://localhost:7657/i2plogo.png" alt="Router Console" width="187" height="35" border="0"/></a><br />
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
</div>
<div class=warning id=warning>

View File

@@ -6,6 +6,7 @@ Proxy-Connection: close
<html><head>
<title>Eepsite not reachable</title>
<link rel="shortcut icon" href="http://localhost:7657/favicon.ico" />
<style type='text/css'>
div.warning {
margin: 0em 1em 1em 224px;
@@ -31,13 +32,13 @@ div.logo {
</head>
<body>
<div class=logo>
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
<a href="http://localhost:7657/index.jsp" title="Router Console"><img src="http://localhost:7657/i2plogo.png" alt="Router Console" width="187" height="35" border="0"/></a><br />
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
</div>
<div class=warning id=warning>
The eepsite was not reachable. Perhaps
the link you are following is
bad. The eepsite could also
be temporarily offline. You may want to
The eepsite was not reachable.
The eepsite is temporarily offline, there is network congestion,
or your router is not yet well-integrated with peers.
You may want to
<a href="javascript: window.location.reload()">retry</a>.
<BR><BR>Could not find the following destination:<BR><BR>

View File

@@ -6,6 +6,7 @@ Proxy-Connection: close
<html><head>
<title>Invalid eepsite destination</title>
<link rel="shortcut icon" href="http://localhost:7657/favicon.ico" />
<style type='text/css'>
div.warning {
margin: 0em 1em 1em 224px;
@@ -31,7 +32,7 @@ div.logo {
</head>
<body>
<div class=logo>
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
<a href="http://localhost:7657/index.jsp" title="Router Console"><img src="http://localhost:7657/i2plogo.png" alt="Router Console" width="187" height="35" border="0"/></a><br />
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
</div>
<div class=warning id=warning>

View File

@@ -6,6 +6,7 @@ Proxy-Connection: close
<html><head>
<title>Eepsite unknown</title>
<link rel="shortcut icon" href="http://localhost:7657/favicon.ico" />
<style type='text/css'>
div.warning {
margin: 0em 1em 1em 224px;
@@ -31,14 +32,13 @@ div.logo {
</head>
<body>
<div class=logo>
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
<a href="http://localhost:7657/index.jsp" title="Router Console"><img src="http://localhost:7657/i2plogo.png" alt="Router Console" width="187" height="35" border="0"/></a><br />
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
</div>
<div class=warning id=warning>
The eepsite was not found in your router's addressbook.
Check the link or find a BASE64 address.
If you have the BASE64 address, paste it into your userhosts.txt using SusiDNS
<a href="http://localhost:7657/susidns/addressbook.jsp?book=master">here</a>.
or use a BASE64 address helper.
You may be able to find the eepsite's address helper at <a href="http://orion.i2p">orion.i2p</a>.
If you have the BASE64 address, paste it into your userhosts.txt using
<a href="http://localhost:7657/susidns/addressbook.jsp?book=master">SusiDNS</a>,
use a BASE64 address helper, or use a jump service link below.
<BR><BR>Could not find the following destination:<BR><BR>

View File

@@ -6,6 +6,7 @@ Proxy-Connection: close
<html><head>
<title>Outproxy Not Found</title>
<link rel="shortcut icon" href="http://localhost:7657/favicon.ico" />
<style type='text/css'>
div.warning {
margin: 0em 1em 1em 224px;
@@ -32,13 +33,14 @@ div.logo {
</head>
<body>
<div class=logo>
<a href="http://localhost:7657/index.jsp">Router Console</a><br />
<a href="http://localhost:7657/index.jsp" title="Router Console"><img src="http://localhost:7657/i2plogo.png" alt="Router Console" width="187" height="35" border="0"/></a><br />
[<a href="http://localhost:7657/config.jsp">configuration</a> | <a href="http://localhost:7657/help.jsp">help</a>]
</div>
<div class=warning id=warning>
The WWW Outproxy was not found.
It could
be temporarily offline. You may want to
It is offline, there is network congestion,
or your router is not yet well-integrated with peers.
You may want to
<a href="javascript: parent.window.location.reload()">retry</a>
as this will randomly reselect an outproxy from the pool you have defined
<a href="http://localhost:7657/i2ptunnel/index.jsp">here</a>

View File

@@ -1,4 +1,4 @@
#!/bin/sh
#export I2P=~i2p/i2p
export I2P=.
export I2P=`dirname $0`
java -cp $I2P/lib/i2p.jar net.i2p.util.EepGet $*

View File

@@ -14,16 +14,15 @@
<a href="http://localhost:7657/i2ptunnel/edit.jsp?tunnel=3">configuration page</a>).
The instructions below detail how to assign a name like "mysite.i2p" to your key and
start up your eepsite.</p>
<p>You can also reach your eepsite locally through
<a href="http://localhost:7658/">http://localhost:7658/</a>. If you
want to change the port number, edit the file ./eepsite/jetty.xml and
update the I2PTunnel configuration accordingly.</p>
<p>You can reach your eepsite locally through
<a href="http://localhost:7658/">http://localhost:7658/</a>.
</p>
<h2>Step-by-step instructions for starting your new eepsite and announcing it to the I2P community</h2>
Your eepsite is stopped by default.
After you start it, it will be difficult for other people to find because it
doesn't have a name and they don't have your really long Base64 key.
You could just tell people that really long key but thankfully i2p has an address book
You could just tell people that really long key, but thankfully i2p has an address book
and several easy ways to tell people about your eepsite. Here's detailed instructions.
<ul>
<li>Pick a name for your eepsite (<i>something</i>.i2p). Use all lower-case.
@@ -52,35 +51,48 @@
<li>Before you tell the world about your new eepsite, you should add some content.
Go to i2p/eepsite/docroot and copy this document (index.html) to help.html so you can refer to it later.
Now edit index.html and add content, pictures, and whatever you would like to share.
<li>Now it's time to add your eepsite to I2P's most popular address book.
To do that, you must to tell <a href="http://orion.i2p/">orion.i2p</a>
what your eepsite name and key are. Orion has a web interface where you can add a key to the address book.
The key entry form is <a href="http://orion.i2p/list/">here</a>.
<li>Now it's time to add your eepsite to an I2P address book hosted by a site
such as <a href="http://stats.i2p/">stats.i2p</a>.
That is, you must enter
your eepsite name and key into a web interface on one or more of these sites.
Here is <a href="http://stats.i2p/i2p/addkey.html">the key entry form at stats.i2p</a>,
and
here is <a href="http://trevorreznik.i2p/host-database/">the key entry form at trevorreznik.i2p</a>.
Again, your key is the entire "Local destination" key on the
<a href="http://localhost:7657/i2ptunnel/edit.jsp?tunnel=3">eepsite i2ptunnel configuration page</a>.
Be sure you get the whole thing, ending with "AAAA".
Don't forget to click "add a key".
Check to see if it reports the key was added.
Since most routers periodically get address book updates from orion, within several hours others will be able to find your
Since many routers periodically get address book updates from these sites, within several hours others will be able to find your
website by simply typing <i>something</i>.i2p into their browser.
<li>If you are in a hurry and can't wait a few hours, you can tell people to use orion's "jump" address helper redirection service.
This will work within a few minutes of your entering the key to orion.i2p.
Test it yourself first by entering http://orion.i2p/jump/<i>something</i>.i2p into your browser.
<li>Speaking of address book updates, this would be a good time to add some more addressbooks
to your own subscription list. Go to your <a href="http://localhost:7657/susidns/subscriptions.jsp">subscriptions configuration page</a>
and add a couple of these -
<a href="http://tino.i2p/hosts.txt">http://tino.i2p/hosts.txt</a>,
<a href="http://stats.i2p/cgi-bin/newhosts.txt">http://stats.i2p/cgi-bin/newhosts.txt</a>,
<a href="http://trevorreznik.i2p/hosts.txt">http://trevorreznik.i2p/hosts.txt</a> and hit "Save".
Now you will get updates too!
<li>If you are in a hurry and can't wait a few hours, you can tell people to use a "jump" address helper redirection service.
This will work within a few minutes of your entering the key to an address book.
Test it yourself first by entering
http://stats.i2p/cgi-bin/jump.cgi?a=<i>something</i>.i2p or
or http://trevorreznik.i2p/cgi-bin/jump.php?hostname=<i>something</i>.i2p into your browser.
Once it's working, then you can tell others to use it.
<li>Some people check <a href="http://orion.i2p/list/">orion.i2p/list/</a> for new eepsites, so you may start getting
<li>Some people check eepsite lists such as
<a href="http://inproxy.tino.i2p/status.php">inproxy.tino.i2p/status.php</a> for new eepsites, so you may start getting
a few visitors. But there are plenty of other ways to tell people. Here are a few ideas:
<ul>
<li>Post a message on the <a href="http://forum.i2p/viewforum.php?f=16">Eepsite announce forum</a>
on <a href="http://forum.i2p/">forum.i2p</a>.
<li>Tell people about it on the #i2p or #i2p-chat channels on IRC.
<li>Put it in a new post on <a href="syndie.i2p.net">the new Syndie</a>.
<li>Put it in a new post on <a href="http://syndie.i2p2.de/">the new Syndie</a>.
<li>Put it in <a href="http://ugha.i2p/EepsiteIndex">Ugha's Eepsite Index Wiki</a>
</ul>
Note that some sites recommend pasting in that really long destination key.
You can if you want - but
if you have successfully posted your key on the <a href="http://orion.i2p/list/">orion page here</a>,
tested it using http://orion.i2p/jump/<i>something</i>.i2p, and waited 24 hours for orion's
address book to propagate to others, that shouldn't be necessary.
if you have successfully posted your key at an add-key service,
tested it using a jump service, and waited 24 hours for the
address book update to propagate to others, that shouldn't be necessary.
<li>If you have any questions try IRC #i2p or the
<a href="http://forum.i2p/viewforum.php?f=10">technical problems section</a> on
<a href="http://forum.i2p/">forum.i2p</a>.

View File

@@ -5,7 +5,7 @@ tunnel.0.type=httpclient
tunnel.0.sharedClient=true
tunnel.0.interface=127.0.0.1
tunnel.0.listenPort=4444
tunnel.0.proxyList=squid.i2p
tunnel.0.proxyList=true.i2p,krabs.i2p
tunnel.0.i2cpHost=127.0.0.1
tunnel.0.i2cpPort=7654
tunnel.0.option.inbound.nickname=shared clients
@@ -29,14 +29,14 @@ tunnel.1.option.i2p.streaming.connectDelay=1000
tunnel.1.option.i2p.streaming.maxWindowSize=1
tunnel.1.startOnLoad=true
# I2P's cvs server
tunnel.2.name=cvs.i2p
tunnel.2.description=I2P CVS pserver
# I2P's mtn server
tunnel.2.name=mtn.i2p2.i2p
tunnel.2.description=I2P Monotone Server
tunnel.2.type=client
tunnel.2.sharedClient=true
tunnel.2.interface=127.0.0.1
tunnel.2.listenPort=2401
tunnel.2.targetDestination=cvs.i2p
tunnel.2.listenPort=8998
tunnel.2.targetDestination=mtn.i2p2.i2p
tunnel.2.i2cpHost=127.0.0.1
tunnel.2.i2cpPort=7654
tunnel.2.option.inbound.nickname=shared clients

View File

@@ -25,7 +25,7 @@
</Arg>
<Set name="MinThreads">3</Set>
<Set name="MaxThreads">10</Set>
<Set name="MaxIdleTimeMs">30000</Set>
<Set name="MaxIdleTimeMs">60000</Set>
<Set name="LowResourcePersistTimeMs">1000</Set>
<Set name="ConfidentialPort">8443</Set>
<Set name="IntegralPort">8443</Set>

View File

@@ -1,3 +1,10 @@
#
# This runs the router by itself, WITHOUT the wrapper.
# This means the router will not restart if it crashes.
# Also, you will be using the default memory size, which is
# probably not enough for i2p.
# You should really use the i2prouter script instead.
#
export CP=. ; for j in lib/* ; do export CP=$CP:$j ; done;
JAVA=java

View File

@@ -1,5 +1,11 @@
#********************************************************************
# Wrapper Properties
#
# WARNING - for any changes to take effect, you must completely
# stop the router and the wrapper. Clicking 'Restart' on your
# router console will NOT reread this file! You must
# click "Shutdown", wait 11 minutes, then start i2p.
#
#********************************************************************
# Java Application
wrapper.java.command=java
@@ -60,6 +66,13 @@ wrapper.java.additional.4=-Dorg.mortbay.xml.XmlParser.NotValidating=true
# The JVM's default is 64MB, and I2P can work fine in that, but to handle
# lots of I2PSnark activity in the same JVM, increasing the default max heap
# size should help. Feel free to reduce this if not using I2PSnark in the jvm
# High-bandwidth routers may need to increase to 256 or more.
#
# WARNING - for any changes to take effect, you must completely
# stop the router and the wrapper. Clicking 'Restart' on your
# router console will NOT reread this file! You must
# click "Shutdown", wait 11 minutes, then start i2p.
#
wrapper.java.maxmemory=128
# Application parameters. Add parameters as needed starting from 1

View File

@@ -1,5 +1,5 @@
<i2p.news date="$Date: 2007-07-19 13:05:44 $">
<i2p.release version="0.6.1.29" date="2007/02/15" minVersion="0.6"
<i2p.news date="$Date: 2008-04-26 15:00:00 $">
<i2p.release version="0.6.1.33" date="2008/04/26" minVersion="0.6"
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"
@@ -9,27 +9,37 @@
publicurl="http://dev.i2p.net/pipermail/i2p/2005-July/000826.html"
anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting141"
publiclogs="http://www.i2p.net/meeting141" />
<p>
&#149;
2007-07-19:
We need bandwidth!
Please help the network by
<a href="/config.jsp">increasing your bandwidth limits and share percentage</a>.
Unless the share percentage times the minimum rate is more than 16KBps,
you are not sharing at all!
Increasing your rate limits will also help your own transfer rates.
Thanks!
<br />
2008-04-26: <b>0.6.1.33 <a href="http://www.i2p2.i2p/release-0.6.1.33.html">Released</a></b>
</p><p>
The 0.6.1.33 release contains several important bug fixes and performance improvements
in SSU reachability detection, floodfill peer selection, tunnel peer selection, tunnel testing,
NTCP idle detection, the streaming lib, and news fetching.
It also adds secondary tracker support to i2psnark.
Please upgrade as soon as you can, as these fixes
should improve the reliability of the whole network.
</p>
<p>
&#149;
2007-03-17: 0.6.1.28
<a href="http://dev.i2p/pipermail/i2p/2007-March/001340.html">released</a>
with
streaming lib optimizations, i2psnark
improvements, and priority operation within the router.
<br />
2008-04-20: <b><a href="http://trac.i2p2.i2p/">We are now using Trac as bugtracker</a></b>
</p>
<p>
&#149;
2008-02-05: <b>Upgrading from 0.6.1.30 and Earlier Releases</b>
</p><p>
Full instructions are posted at
<a href="http://www.i2p2.i2p/upgrade-0.6.1.30.html">www.i2p2.i2p/upgrade-0.6.1.30.html</a>.
</p>
<!--
&#149;
2007-04-10:
<a href="http://dev.i2p/pipermail/i2p/2007-April/001343.html">status notes</a>
and
<a href="http://www.i2p/meeting206">meeting log</a>
<br />
-->
</i2p.news>

View File

@@ -3,22 +3,18 @@ grow over the next few minutes and you'll see a "shared clients" local destinati
on the left (if not, <a href="#trouble">see below</a>). Once those show up,
you can:</p>
<ul>
<li><b>blog anonymously</b> - check out <a href="http://syndie.i2p/">Syndie</a></li>
<li><b>chat anonymously</b> - fire up your own IRC client and connect to the
server at <b>localhost port 6668</b>. This points at one of two anonymously hosted
IRC servers, but neither you nor they know where the other is.</li>
<li><b>browse "eepsites"</b> - on I2P there are anonymously hosted websites -
tell your browser to use the <b>HTTP proxy at localhost port 4444</b>, then
browse to an eepsite -
<ul>
<li><a href="http://orion.i2p/">orion.i2p</a>: a site which tracks eepsite uptime and changes</li>
<li><a href="http://inproxy.tino.i2p/status.php">inproxy.tino.i2p</a>: a site which tracks active eepsites</li>
<li><a href="http://forum.i2p/">forum.i2p</a>: a secure and anonymous connection to <a href="http://forum.i2p.net/">forum.i2p.net</a></li>
<li><a href="http://www.i2p/">www.i2p</a>: a secure and anonymous connection to <a href="http://www.i2p.net/">www.i2p.net</a></li>
<li><a href="http://inproxy.tino.i2p/status.php">inproxy.tino.i2p</a> and
<a href="http://perv.i2p/stats.cgi">perv.i2p</a>: sites tracking active eepsites</li>
<li><a href="http://forum.i2p/">forum.i2p</a>: a secure and anonymous connection to <a href="http://forum.i2p2.de/">forum.i2p2.de</a></li>
<li><a href="http://www.i2p2.i2p/">www.i2p2.i2p</a> and mirror <a href="http://i2p-projekt.i2p">i2p-projekt.i2p</a>:
secure and anonymous connections to <a href="http://www.i2p2.de/">www.i2p2.de</a></li>
<li><a href="http://eepsites.i2p/">eepsites.i2p</a>: an anonymously hosted search engine of eepsites</li>
<li><a href="http://ugha.i2p/">ugha.i2p</a>: ugha's eepsite, a wiki that anyone can edit, and lots of links</li>
<li><a href="http://dev.i2p/">dev.i2p</a>: a secure and anonymous connection to <a href="http://dev.i2p.net/">dev.i2p.net</a></li>
<li>Freenet proxy: <a href="http://fproxy.tino.i2p">fproxy.tino.i2p</a></li>
<li><a href="http://fproxy.tino.i2p">fproxy.tino.i2p</a>: Freenet proxy</li>
</ul>
There are many more eepsites - just follow the links from the ones you see,
bookmark your favorites, and visit them often!</li>
@@ -32,8 +28,12 @@ you can:</p>
<li><b>use anonymous email</b> - postman has created a mail system compatible with normal mail
clients (POP3 / SMTP) that allows email within I2P as well as mail from and to the normal
internet! get your account at <a href="http://hq.postman.i2p/">hq.postman.i2p</a>.
We bundle <a href="http://susi.i2p/">Susi's</a> <a href="/susimail/susimail">susimail</a>,
We bundle <a href="/susimail/susimail">susimail</a>,
a web based anonymity-oriented pop3/smtp client configured to access postman's mail services.</li>
<li><b>chat anonymously</b> - fire up your own IRC client and connect to the
server at <b>localhost port 6668</b>. This points at one of two anonymously hosted
IRC servers, but neither you nor they know where the other is.</li>
<li><b>blog anonymously</b> - check out <a href="http://syndie.i2p2.de/">Syndie</a></li>
<li>and lots more</li>
</ul>
@@ -55,11 +55,11 @@ Detailed instructions for starting your eepsite are on
<p>Be patient - I2P may be slow to start the first time as it searches for peers.
If, after 30 minutes, your Active: connected/recent count has less than 10 connected
peers, you should open port 8887 on your firewall for better connectivity.
If you cannot see any eepsites at all (even <a href="http://www.i2p">www.i2p</a>),
If you cannot see any eepsites at all (even <a href="http://www.i2p2.i2p/">www.i2p2.i2p</a>),
be sure your browser proxy is set to localhost port 4444.
You may also want to review the information on the
<a href="http://www.i2p.net/">I2P website</a>, post up messages to the
<a href="http://forum.i2p.net/">I2P discussion forum</a>, or swing by #i2p or
<a href="http://www.i2p2.i2p/">I2P website</a>, post up messages to the
<a href="http://forum.i2p2.de/">I2P discussion forum</a>, or swing by #i2p or
#i2p-chat on IRC at <a href="irc://irc.freenode.net/#i2p">irc.freenode.net</a>, irc.postman.i2p or irc.freshcoffee.i2p (they're linked together).</p>
<p><b>As a note, you can change this page by editing the file "docs/readme.html"</b></p>

View File

@@ -33,8 +33,8 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl {
public DatabaseSearchReplyMessage(I2PAppContext context) {
super(context);
_context.statManager().createRateStat("netDb.searchReplyMessageSend", "How many search reply messages we send", "Network Database", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("netDb.searchReplyMessageReceive", "How many search reply messages we receive", "Network Database", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("netDb.searchReplyMessageSend", "How many search reply messages we send", "NetworkDatabase", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
_context.statManager().createRateStat("netDb.searchReplyMessageReceive", "How many search reply messages we receive", "NetworkDatabase", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 });
setSearchKey(null);
_peerHashes = new ArrayList(3);
setFromHash(null);

View File

@@ -14,6 +14,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.i2p.data.Hash;
import net.i2p.data.RouterAddress;
/**
@@ -52,6 +53,8 @@ public abstract class CommSystemFacade implements Service {
*/
public short getReachabilityStatus() { return STATUS_OK; }
public void recheckReachability() {}
public boolean isBacklogged(Hash dest) { return false; }
public boolean wasUnreachable(Hash dest) { return false; }
/**
* Tell other transports our address changed

View File

@@ -939,6 +939,10 @@ public class Router {
for (Iterator iter = ordered.iterator() ; iter.hasNext(); ) {
String key = (String)iter.next();
String val = _config.getProperty(key);
// Escape line breaks before saving.
// Remember: "\" needs escaping both for regex and string.
val = val.replaceAll("\\r","\\\\r");
val = val.replaceAll("\\n","\\\\n");
buf.append(key).append('=').append(val).append('\n');
}
}

View File

@@ -15,8 +15,8 @@ import net.i2p.CoreVersion;
*
*/
public class RouterVersion {
public final static String ID = "$Revision: 1.518 $ $Date: 2007-08-13 14:43:01 $";
public final static String VERSION = "0.6.1.29";
public final static String ID = "$Revision: 1.548 $ $Date: 2008-02-10 15:00:00 $";
public final static String VERSION = "0.6.1.33";
public final static long BUILD = 0;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);

View File

@@ -37,7 +37,7 @@ public class Shitlist {
Set transports;
}
public final static long SHITLIST_DURATION_MS = 4*60*1000; // 4 minute shitlist
public final static long SHITLIST_DURATION_MS = 40*60*1000; // 40 minute shitlist
public Shitlist(RouterContext context) {
_context = context;
@@ -72,6 +72,8 @@ public class Shitlist {
if (prof != null)
prof.unshitlist();
_context.messageHistory().unshitlist(peer);
if (_log.shouldLog(Log.INFO))
_log.info("Unshitlisting router (expired) " + peer.toBase64());
}
requeue(30*1000);
@@ -152,12 +154,13 @@ public class Shitlist {
public void unshitlistRouter(Hash peer, String transport) { unshitlistRouter(peer, true, transport); }
private void unshitlistRouter(Hash peer, boolean realUnshitlist, String transport) {
if (peer == null) return;
if (_log.shouldLog(Log.INFO))
_log.info("Unshitlisting router " + peer.toBase64()
if (_log.shouldLog(Log.DEBUG))
_log.debug("Calling unshitlistRouter " + peer.toBase64()
+ (transport != null ? "/" + transport : ""));
boolean fully = false;
Entry e;
synchronized (_entries) {
Entry e = (Entry)_entries.remove(peer);
e = (Entry)_entries.remove(peer);
if ( (e == null) || (e.transports == null) || (transport == null) || (e.transports.size() <= 1) ) {
// fully unshitlisted
fully = true;
@@ -176,6 +179,9 @@ public class Shitlist {
prof.unshitlist();
}
_context.messageHistory().unshitlist(peer);
if (_log.shouldLog(Log.INFO) && e != null)
_log.info("Unshitlisting router " + peer.toBase64()
+ (transport != null ? "/" + transport : ""));
}
}
@@ -209,6 +215,8 @@ public class Shitlist {
if (prof != null)
prof.unshitlist();
_context.messageHistory().unshitlist(peer);
if (_log.shouldLog(Log.INFO))
_log.info("Unshitlisting router (expired) " + peer.toBase64());
}
return rv;

View File

@@ -103,6 +103,7 @@ public class StatisticsManager implements Service {
// stats.setProperty("router.id", RouterVersion.ID);
// stats.setProperty("core.id", CoreVersion.ID);
/***
int newlines = 0;
FileInputStream in = null;
try {
@@ -122,66 +123,76 @@ public class StatisticsManager implements Service {
}
if (newlines > 0)
stats.setProperty("stat_identities", newlines+"");
***/
if (_includePeerRankings) {
if (false)
stats.putAll(_context.profileManager().summarizePeers(_publishedStats));
boolean commentMeOutInDot33 = RouterVersion.VERSION.equals("0.6.1.32");
includeThroughput(stats);
includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 });
//includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
//includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 });
//includeRate("tunnel.duplicateIV", stats, new long[] { 24*60*60*1000 });
includeRate("tunnel.fragmentedDropped", stats, new long[] { 10*60*1000, 3*60*60*1000 });
//includeRate("tunnel.fragmentedDropped", stats, new long[] { 10*60*1000, 3*60*60*1000 });
//includeRate("tunnel.fullFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
//includeRate("tunnel.smallFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
if (commentMeOutInDot33)
includeRate("tunnel.testFailedTime", stats, new long[] { 10*60*1000 });
includeRate("tunnel.buildFailure", stats, new long[] { 60*60*1000 });
includeRate("tunnel.buildSuccess", stats, new long[] { 60*60*1000 });
//includeRate("tunnel.batchDelaySent", stats, new long[] { 10*60*1000, 60*60*1000 });
includeRate("tunnel.batchMultipleCount", stats, new long[] { 10*60*1000, 60*60*1000 });
//includeRate("tunnel.batchMultipleCount", stats, new long[] { 10*60*1000, 60*60*1000 });
includeRate("tunnel.corruptMessage", stats, new long[] { 60*60*1000l, 3*60*60*1000l });
//includeRate("router.throttleTunnelProbTestSlow", stats, new long[] { 60*60*1000 });
//includeRate("router.throttleTunnelProbTooFast", stats, new long[] { 60*60*1000 });
//includeRate("router.throttleTunnelProcessingTime1m", stats, new long[] { 60*60*1000 });
if (commentMeOutInDot33)
includeRate("router.fastPeers", stats, new long[] { 60*60*1000 });
includeRate("udp.statusOK", stats, new long[] { 20*60*1000 });
includeRate("udp.statusDifferent", stats, new long[] { 20*60*1000 });
includeRate("udp.statusReject", stats, new long[] { 20*60*1000 });
includeRate("udp.statusUnknown", stats, new long[] { 20*60*1000 });
includeRate("udp.statusKnownCharlie", stats, new long[] { 1*60*1000, 10*60*1000 });
includeRate("udp.addressUpdated", stats, new long[] { 1*60*1000 });
includeRate("udp.addressTestInsteadOfUpdate", stats, new long[] { 1*60*1000 });
//includeRate("udp.statusOK", stats, new long[] { 20*60*1000 });
//includeRate("udp.statusDifferent", stats, new long[] { 20*60*1000 });
//includeRate("udp.statusReject", stats, new long[] { 20*60*1000 });
//includeRate("udp.statusUnknown", stats, new long[] { 20*60*1000 });
//includeRate("udp.statusKnownCharlie", stats, new long[] { 1*60*1000, 10*60*1000 });
//includeRate("udp.addressUpdated", stats, new long[] { 1*60*1000 });
//includeRate("udp.addressTestInsteadOfUpdate", stats, new long[] { 1*60*1000 });
includeRate("clock.skew", stats, new long[] { 10*60*1000, 3*60*60*1000, 24*60*60*1000 });
//includeRate("transport.sendProcessingTime", stats, new long[] { 60*60*1000 });
//includeRate("jobQueue.jobRunSlow", stats, new long[] { 10*60*1000l, 60*60*1000l });
if (commentMeOutInDot33) { // get rid of 60s stats
includeRate("crypto.elGamal.encrypt", stats, new long[] { 60*1000, 60*60*1000 });
} else {
includeRate("crypto.elGamal.encrypt", stats, new long[] { 60*60*1000 });
}
includeRate("tunnel.participatingTunnels", stats, new long[] { 5*60*1000, 60*60*1000 });
includeRate("tunnel.testSuccessTime", stats, new long[] { 10*60*1000l });
//includeRate("tunnel.testSuccessTime", stats, new long[] { 10*60*1000l });
includeRate("client.sendAckTime", stats, new long[] { 60*60*1000 }, true);
includeRate("udp.sendConfirmTime", stats, new long[] { 10*60*1000 });
includeRate("udp.sendVolleyTime", stats, new long[] { 10*60*1000 });
includeRate("udp.ignoreRecentDuplicate", stats, new long[] { 60*1000 });
includeRate("udp.congestionOccurred", stats, new long[] { 10*60*1000 });
//includeRate("udp.sendConfirmTime", stats, new long[] { 10*60*1000 });
//includeRate("udp.sendVolleyTime", stats, new long[] { 10*60*1000 });
//includeRate("udp.ignoreRecentDuplicate", stats, new long[] { 60*1000 });
//includeRate("udp.congestionOccurred", stats, new long[] { 10*60*1000 });
//includeRate("stream.con.sendDuplicateSize", stats, new long[] { 60*60*1000 });
//includeRate("stream.con.receiveDuplicateSize", stats, new long[] { 60*60*1000 });
// Round smaller uptimes to 1 hour, to frustrate uptime tracking
// Round 2nd hour to 90m since peers use 2h minimum to route
long publishedUptime = _context.router().getUptime();
if (publishedUptime < 60*60*1000) publishedUptime = 60*60*1000;
else if (publishedUptime < 2*60*60*1000 && !commentMeOutInDot33) publishedUptime = 90*60*1000;
stats.setProperty("stat_uptime", DataHelper.formatDuration(publishedUptime));
stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]");
//stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]");
if (commentMeOutInDot33) { // get rid of 60s stats
includeRate("tunnel.buildRequestTime", stats, new long[] { 60*1000, 10*60*1000 });
includeRate("tunnel.decryptRequestTime", stats, new long[] { 60*1000, 10*60*1000 });
//includeRate("tunnel.decryptRequestTime", stats, new long[] { 60*1000, 10*60*1000 });
includeRate("tunnel.buildClientExpire", stats, new long[] { 60*1000, 10*60*1000 });
includeRate("tunnel.buildClientReject", stats, new long[] { 60*1000, 10*60*1000 });
includeRate("tunnel.buildClientSuccess", stats, new long[] { 60*1000, 10*60*1000 });
@@ -189,11 +200,23 @@ public class StatisticsManager implements Service {
includeRate("tunnel.buildExploratoryReject", stats, new long[] { 60*1000, 10*60*1000 });
includeRate("tunnel.buildExploratorySuccess", stats, new long[] { 60*1000, 10*60*1000 });
includeRate("tunnel.rejectTimeout", stats, new long[] { 60*1000, 10*60*1000 });
includeRate("udp.packetDequeueTime", stats, new long[] { 60*1000 });
includeRate("udp.packetVerifyTime", stats, new long[] { 60*1000 });
//includeRate("udp.packetDequeueTime", stats, new long[] { 60*1000 });
//includeRate("udp.packetVerifyTime", stats, new long[] { 60*1000 });
includeRate("tunnel.rejectOverloaded", stats, new long[] { 60*1000, 10*60*1000 });
includeRate("tunnel.acceptLoad", stats, new long[] { 60*1000, 10*60*1000 });
} else {
includeRate("tunnel.buildRequestTime", stats, new long[] { 10*60*1000 });
includeRate("tunnel.buildClientExpire", stats, new long[] { 10*60*1000 });
includeRate("tunnel.buildClientReject", stats, new long[] { 10*60*1000 });
includeRate("tunnel.buildClientSuccess", stats, new long[] { 10*60*1000 });
includeRate("tunnel.buildExploratoryExpire", stats, new long[] { 10*60*1000 });
includeRate("tunnel.buildExploratoryReject", stats, new long[] { 10*60*1000 });
includeRate("tunnel.buildExploratorySuccess", stats, new long[] { 10*60*1000 });
includeRate("tunnel.rejectTimeout", stats, new long[] { 10*60*1000 });
includeRate("tunnel.rejectOverloaded", stats, new long[] { 10*60*1000 });
includeRate("tunnel.acceptLoad", stats, new long[] { 10*60*1000 });
}
if (FloodfillNetworkDatabaseFacade.isFloodfill(_context.router().getRouterInfo())) {
stats.setProperty("netdb.knownRouters", ""+_context.netDb().getKnownRouters());

View File

@@ -41,6 +41,9 @@ public interface TunnelManagerFacade extends Service {
*
*/
boolean isInUse(Hash peer);
/** Is a tunnel a valid member of the pool? */
public boolean isValidTunnel(Hash client, TunnelInfo tunnel);
/** how many tunnels are we participating in? */
public int getParticipatingCount();
@@ -85,6 +88,7 @@ class DummyTunnelManagerFacade implements TunnelManagerFacade {
public TunnelInfo selectOutboundTunnel() { return null; }
public TunnelInfo selectOutboundTunnel(Hash destination) { return null; }
public boolean isInUse(Hash peer) { return false; }
public boolean isValidTunnel(Hash client, TunnelInfo tunnel) { return false; }
public int getParticipatingCount() { return 0; }
public int getFreeTunnelCount() { return 0; }
public int getOutboundTunnelCount() { return 0; }

View File

@@ -4,6 +4,7 @@ import java.util.Iterator;
import java.util.Properties;
import net.i2p.data.Hash;
import net.i2p.util.RandomSource;
/**
* Wrap up the settings for a pool of tunnels (duh)
@@ -14,7 +15,7 @@ public class TunnelPoolSettings {
private String _destinationNickname;
private int _quantity;
private int _backupQuantity;
private int _rebuildPeriod;
// private int _rebuildPeriod;
private int _duration;
private int _length;
private int _lengthVariance;
@@ -22,7 +23,9 @@ public class TunnelPoolSettings {
private boolean _isInbound;
private boolean _isExploratory;
private boolean _allowZeroHop;
private int _IPRestriction;
private Properties _unknownOptions;
private Hash _randomKey;
/** prefix used to override the router's defaults for clients */
public static final String PREFIX_DEFAULT = "router.defaultPool.";
@@ -34,24 +37,26 @@ public class TunnelPoolSettings {
public static final String PROP_NICKNAME = "nickname";
public static final String PROP_QUANTITY = "quantity";
public static final String PROP_BACKUP_QUANTITY = "backupQuantity";
public static final String PROP_REBUILD_PERIOD = "rebuildPeriod";
// public static final String PROP_REBUILD_PERIOD = "rebuildPeriod";
public static final String PROP_DURATION = "duration";
public static final String PROP_LENGTH = "length";
public static final String PROP_LENGTH_VARIANCE = "lengthVariance";
public static final String PROP_ALLOW_ZERO_HOP = "allowZeroHop";
public static final String PROP_IP_RESTRICTION = "IPRestriction";
public static final int DEFAULT_QUANTITY = 2;
public static final int DEFAULT_BACKUP_QUANTITY = 0;
public static final int DEFAULT_REBUILD_PERIOD = 60*1000;
// public static final int DEFAULT_REBUILD_PERIOD = 60*1000;
public static final int DEFAULT_DURATION = 10*60*1000;
public static final int DEFAULT_LENGTH = 2;
public static final int DEFAULT_LENGTH_VARIANCE = 1;
public static final boolean DEFAULT_ALLOW_ZERO_HOP = true;
public static final int DEFAULT_IP_RESTRICTION = 2; // class B (/16)
public TunnelPoolSettings() {
_quantity = DEFAULT_QUANTITY;
_backupQuantity = DEFAULT_BACKUP_QUANTITY;
_rebuildPeriod = DEFAULT_REBUILD_PERIOD;
// _rebuildPeriod = DEFAULT_REBUILD_PERIOD;
_duration = DEFAULT_DURATION;
_length = DEFAULT_LENGTH;
_lengthVariance = DEFAULT_LENGTH_VARIANCE;
@@ -61,7 +66,9 @@ public class TunnelPoolSettings {
_isExploratory = false;
_destination = null;
_destinationNickname = null;
_IPRestriction = DEFAULT_IP_RESTRICTION;
_unknownOptions = new Properties();
_randomKey = generateRandomKey();
}
/** how many tunnels should be available at all times */
@@ -73,8 +80,8 @@ public class TunnelPoolSettings {
public void setBackupQuantity(int quantity) { _backupQuantity = quantity; }
/** how long before tunnel expiration should new tunnels be built */
public int getRebuildPeriod() { return _rebuildPeriod; }
public void setRebuildPeriod(int periodMs) { _rebuildPeriod = periodMs; }
// public int getRebuildPeriod() { return _rebuildPeriod; }
// public void setRebuildPeriod(int periodMs) { _rebuildPeriod = periodMs; }
/** how many remote hops should be in the tunnel */
public int getLength() { return _length; }
@@ -112,10 +119,22 @@ public class TunnelPoolSettings {
public Hash getDestination() { return _destination; }
public void setDestination(Hash dest) { _destination = dest; }
/** random key used for peer ordering */
public Hash getRandomKey() { return _randomKey; }
/** what user supplied name was given to the client connected (can be null) */
public String getDestinationNickname() { return _destinationNickname; }
public void setDestinationNickname(String name) { _destinationNickname = name; }
/**
* How many bytes to match to determine if a router's IP is too close to another's
* to be in the same tunnel
* (1-4, 0 to disable)
*
*/
public int getIPRestriction() { int r = _IPRestriction; if (r>4) r=4; else if (r<0) r=0; return r;}
public void setIPRestriction(int b) { _IPRestriction = b; }
public Properties getUnknownOptions() { return _unknownOptions; }
public void readFromProperties(String prefix, Properties props) {
@@ -135,10 +154,12 @@ public class TunnelPoolSettings {
_lengthVariance = getInt(value, DEFAULT_LENGTH_VARIANCE);
else if (name.equalsIgnoreCase(prefix + PROP_QUANTITY))
_quantity = getInt(value, DEFAULT_QUANTITY);
else if (name.equalsIgnoreCase(prefix + PROP_REBUILD_PERIOD))
_rebuildPeriod = getInt(value, DEFAULT_REBUILD_PERIOD);
// else if (name.equalsIgnoreCase(prefix + PROP_REBUILD_PERIOD))
// _rebuildPeriod = getInt(value, DEFAULT_REBUILD_PERIOD);
else if (name.equalsIgnoreCase(prefix + PROP_NICKNAME))
_destinationNickname = value;
else if (name.equalsIgnoreCase(prefix + PROP_IP_RESTRICTION))
_IPRestriction = getInt(value, DEFAULT_IP_RESTRICTION);
else
_unknownOptions.setProperty(name.substring((prefix != null ? prefix.length() : 0)), value);
}
@@ -155,7 +176,8 @@ public class TunnelPoolSettings {
if (_destinationNickname != null)
props.setProperty(prefix + PROP_NICKNAME, ""+_destinationNickname);
props.setProperty(prefix + PROP_QUANTITY, ""+_quantity);
props.setProperty(prefix + PROP_REBUILD_PERIOD, ""+_rebuildPeriod);
// props.setProperty(prefix + PROP_REBUILD_PERIOD, ""+_rebuildPeriod);
props.setProperty(prefix + PROP_IP_RESTRICTION, ""+_IPRestriction);
for (Iterator iter = _unknownOptions.keySet().iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
String val = _unknownOptions.getProperty(name);
@@ -180,8 +202,12 @@ public class TunnelPoolSettings {
return buf.toString();
}
////
////
// used for strict peer ordering
private Hash generateRandomKey() {
byte hash[] = new byte[Hash.HASH_LENGTH];
RandomSource.getInstance().nextBytes(hash);
return new Hash(hash);
}
private static final boolean getBoolean(String str, boolean defaultValue) {
if (str == null) return defaultValue;

View File

@@ -2,6 +2,7 @@ package net.i2p.router.message;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -15,6 +16,7 @@ import net.i2p.data.Hash;
import net.i2p.data.Lease;
import net.i2p.data.LeaseSet;
import net.i2p.data.PublicKey;
import net.i2p.data.RouterInfo;
import net.i2p.data.SessionKey;
import net.i2p.data.Payload;
import net.i2p.data.i2cp.MessageId;
@@ -189,6 +191,9 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
_log.warn(getJobId() + ": Bundle leaseSet probability overridden incorrectly ["
+ str + "]", nfe);
}
if (probability >= 100)
return true;
_log.error(getJobId() + ": Bundle leaseSet probability is " + probability);
if (probability >= getContext().random().nextInt(100))
return true;
else
@@ -198,7 +203,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
}
}
/** send a message to a random lease */
/** send a message to a lease */
private class SendJob extends JobImpl {
public SendJob(RouterContext enclosingContext) {
super(enclosingContext);
@@ -221,11 +226,22 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
}
/**
* Use the same inbound tunnel (i.e. lease) as we did for the same destination previously,
* if possible, to keep the streaming lib happy
* Key the cache just on the dest, not on source+dest, as different sources
* simultaneously talking to the same dest is probably rare enough
* to not bother separating out.
*
* We're going to use the lease until it expires, as long as it remains in the current leaseSet.
*
* If not found,
* fetch the next lease that we should try sending through, randomly chosen
* from within the sorted leaseSet (sorted by # of failures through each
* from within the sorted leaseSet (NOT sorted by # of failures through each
* lease).
*
*/
private static HashMap _leaseCache = new HashMap();
private static long _lcleanTime = 0;
private boolean getNextLease() {
_leaseSet = getContext().netDb().lookupLeaseSetLocally(_to.calculateHash());
if (_leaseSet == null) {
@@ -234,7 +250,36 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
return false;
}
long now = getContext().clock().now();
/*** removed until we fix SSU reachability
// Use the same lease if it's still good
// Even if _leaseSet changed, _leaseSet.getEncryptionKey() didn't...
synchronized (_leaseCache) {
if (now - _cleanTime > 5*60*1000) { // clean out periodically
cleanLeaseCache(_leaseCache);
_cleanTime = now;
}
_lease = (Lease) _leaseCache.get(_to);
if (_lease != null) {
// if outbound tunnel length == 0 && lease.firsthop.isBacklogged() don't use it ??
if (!_lease.isExpired(Router.CLOCK_FUDGE_FACTOR)) {
// see if the current leaseSet contains the old lease, so that if the dest removes
// it (due to failure for example) we won't continue to use it.
for (int i = 0; i < _leaseSet.getLeaseCount(); i++) {
Lease lease = _leaseSet.getLease(i);
if (_lease.equals(lease)) {
if (_log.shouldLog(Log.INFO))
_log.info("Found in cache - lease for " + _toString);
return true;
}
}
}
if (_log.shouldLog(Log.WARN))
_log.warn("Expired from cache - lease for " + _toString);
_leaseCache.remove(_to);
}
}
***/
// get the possible leases
List leases = new ArrayList(_leaseSet.getLeaseCount());
for (int i = 0; i < _leaseSet.getLeaseCount(); i++) {
@@ -258,6 +303,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
// sort are randomly ordered)
Collections.shuffle(leases);
/****
if (false) {
// ordered by lease number of failures
TreeMap orderedLeases = new TreeMap();
@@ -273,8 +319,39 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
_lease = (Lease)orderedLeases.get(orderedLeases.firstKey());
} else {
_lease = (Lease)leases.get(0);
****/
// Avoid a lease on a gateway we think is unreachable, if possible
for (int i = 0; i < leases.size(); i++) {
Lease l = (Lease) leases.get(i);
/***
*** Anonymity concerns with this, as the dest could act unreachable just to us, then
*** look at our lease selection.
*** Let's just look at whether the gw thinks it is unreachable instead -
*** unfortunately the "U" is rarely seen.
if (!getContext().commSystem().wasUnreachable(l.getGateway())) {
***/
RouterInfo ri = getContext().netDb().lookupRouterInfoLocally(l.getGateway());
if (ri == null || ri.getCapabilities().indexOf(Router.CAPABILITY_UNREACHABLE) < 0) {
_lease = l;
break;
}
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Skipping unreachable gateway " + l.getGateway() + " for " + _toString);
}
if (_lease == null) {
_lease = (Lease)leases.get(0);
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": All leases are unreachable for " + _toString);
}
/*** removed until we fix SSU reachability
synchronized (_leaseCache) {
_leaseCache.put(_to, _lease);
}
if (_log.shouldLog(Log.WARN))
_log.warn("Added to cache - lease for " + _toString);
***/
return true;
}
@@ -378,7 +455,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
+ _lease.getTunnelId() + " on "
+ _lease.getGateway().toBase64());
_outTunnel = selectOutboundTunnel();
_outTunnel = selectOutboundTunnel(_to);
if (_outTunnel != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": Sending tunnel message out " + _outTunnel.getSendTunnelId(0) + " to "
@@ -434,6 +511,103 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
}
}
/**
* Clean out old leases from a set.
* Caller must synchronize on tc.
*/
private void cleanLeaseCache(HashMap tc) {
List deleteList = new ArrayList();
for (Iterator iter = tc.keySet().iterator(); iter.hasNext(); ) {
Destination dest = (Destination) iter.next();
Lease l = (Lease) tc.get(dest);
if (l.isExpired(Router.CLOCK_FUDGE_FACTOR))
deleteList.add(dest);
}
for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) {
Destination dest = (Destination) iter.next();
tc.remove(dest);
}
}
/**
* Clean out old tunnels from a set.
* Caller must synchronize on tc.
*/
private void cleanTunnelCache(HashMap tc) {
List deleteList = new ArrayList();
for (Iterator iter = tc.keySet().iterator(); iter.hasNext(); ) {
Destination dest = (Destination) iter.next();
TunnelInfo tunnel = (TunnelInfo) tc.get(dest);
if (!getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel))
deleteList.add(dest);
}
for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) {
Destination dest = (Destination) iter.next();
tc.remove(dest);
}
}
/**
* Use the same outbound tunnel as we did for the same destination previously,
* if possible, to keep the streaming lib happy
* Use two caches - although a cache of a list of tunnels per dest might be
* more elegant.
* Key the caches just on the dest, not on source+dest, as different sources
* simultaneously talking to the same dest is probably rare enough
* to not bother separating out.
*
*/
private static HashMap _tunnelCache = new HashMap();
private static HashMap _backloggedTunnelCache = new HashMap();
private static long _cleanTime = 0;
private TunnelInfo selectOutboundTunnel(Destination to) {
TunnelInfo tunnel;
long now = getContext().clock().now();
synchronized (_tunnelCache) {
if (now - _cleanTime > 5*60*1000) { // clean out periodically
cleanTunnelCache(_tunnelCache);
cleanTunnelCache(_backloggedTunnelCache);
_cleanTime = now;
}
/**
* If old tunnel is valid and no longer backlogged, use it.
* This prevents an active anonymity attack, where a peer could tell
* if you were the originator by backlogging the tunnel, then removing the
* backlog and seeing if traffic came back or not.
*/
tunnel = (TunnelInfo) _backloggedTunnelCache.get(to);
if (tunnel != null) {
if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) {
if (!getContext().commSystem().isBacklogged(tunnel.getPeer(1))) {
if (_log.shouldLog(Log.WARN))
_log.warn("Switching back to tunnel " + tunnel + " for " + _toString);
_backloggedTunnelCache.remove(to);
_tunnelCache.put(to, tunnel);
return tunnel;
} // else still backlogged
} else // no longer valid
_backloggedTunnelCache.remove(to);
}
// Use the same tunnel unless backlogged
tunnel = (TunnelInfo) _tunnelCache.get(to);
if (tunnel != null) {
if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) {
if (tunnel.getLength() <= 1 || !getContext().commSystem().isBacklogged(tunnel.getPeer(1)))
return tunnel;
// backlogged
if (_log.shouldLog(Log.WARN))
_log.warn("Switching from backlogged " + tunnel + " for " + _toString);
_backloggedTunnelCache.put(to, tunnel);
} // else no longer valid
_tunnelCache.remove(to);
}
// Pick a new tunnel
tunnel = selectOutboundTunnel();
if (tunnel != null)
_tunnelCache.put(to, tunnel);
}
return tunnel;
}
/**
* Pick an arbitrary outbound tunnel to send the message through, or null if
* there aren't any around
@@ -461,8 +635,9 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
long sendTime = getContext().clock().now() - _start;
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Failed to send the message " + _clientMessageId + " after "
+ sendTime + "ms");
_log.warn(getJobId() + ": Failed to send the message " + _clientMessageId + " to " + _toString +
" out " + _outTunnel + " in " + _lease + " ack " + _inTunnel +
" after " + sendTime + "ms");
long messageDelay = getContext().throttle().getMessageDelay();
long tunnelLag = getContext().throttle().getTunnelLag();

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